Skip to content

Commit

Permalink
Initial AirPods decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
DigiH committed Nov 1, 2024
1 parent d6fdd20 commit d6974eb
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 6 deletions.
9 changes: 6 additions & 3 deletions docs/participate/adding-decoders.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ Each device should also have an encoded **tag** property to, at the minimum, def
</thead>
<tbody>
<tr>
<td rowspan=21>Byte[0]</td>
<td rowspan=21>Device Type > "type":</td>
<td rowspan=22>Byte[0]</td>
<td rowspan=22>Device Type > "type":</td>
<td rowspan=1>0 - Reserved</td>
</tr>
<tr>
Expand Down Expand Up @@ -109,7 +109,10 @@ Each device should also have an encoded **tag** property to, at the minimum, def
<td rowspan=1>17 - BTN - button</td>
</tr>
<tr>
<td rowspan=1>18-253 - Reserved</td>
<td rowspan=1>18 - AUDIO - audio devices</td>
</tr>
<tr>
<td rowspan=1>19-253 - Reserved</td>
</tr>
<tr>
<td rowspan=1>254 - RMAC - known random MAC address devices</td>
Expand Down
3 changes: 3 additions & 0 deletions src/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,9 @@ int TheengsDecoder::decodeBLEJson(JsonObject& jsondata) {
case 17:
doc["type"] = "BTN"; // Button
break;
case 18:
doc["type"] = "AUDIO"; // Button
break;
case 254:
doc["type"] = "RMAC"; // random MAC address devices
break;
Expand Down
1 change: 1 addition & 0 deletions src/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class TheengsDecoder {
GTAG,
BOSCHNYON,
JAALEE,
APPLEAIRPODS,
APPLEWATCH,
APPLEDEVICE,
IBEACON,
Expand Down
2 changes: 2 additions & 0 deletions src/devices.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
#include "devices/BM6_json.h"
#include "devices/TILT_json.h"
#include "devices/JAALEE_json.h"
#include "devices/APPLEAIRPODS_json.h"
#include "devices/APPLEWATCH_json.h"
#include "devices/APPLEDEVICE_json.h"
#include "devices/iBeacon_json.h"
Expand Down Expand Up @@ -227,6 +228,7 @@ const char* _devices[][2] = {
{_tracker_json_GTAG, _tracker_json_props},
{_tracker_json_NYON, _tracker_json_props},
{_JAALEE_json, _JAALEE_json_props},
{_APPLEAIRPODS_json, _APPLEAIRPODS_json_props},
{_APPLEWATCH_json, _APPLEWATCH_json_props},
{_APPLEDEVICE_json, _APPLEDEVICE_json_props},
{_ibeacon_json, _ibeacon_json_props},
Expand Down
122 changes: 122 additions & 0 deletions src/devices/APPLEAIRPODS_json.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
const char* _APPLEAIRPODS_json = "{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"tag\":\"1208\",\"condition\":[\"manufacturerdata\",\"index\",8,\"01\",\"&\",\"manufacturerdata\",\"=\",58,\"index\",0,\"4c0007\"],\"properties\":{\"version\":{\"decoder\":[\"static_value\",\"thus far unknown - please report your model version\"]},\"_version\":{\"decoder\":[\"string_from_hex_data\",\"manufacturerdata\",10,4],\"lookup\":[\"0220\",\"AirPods 1st gen.\",\"0e20\",\"AirPods Pro 1st gen.\",\"1420\",\"AirPods Pro 2nd gen.\",\"0320\",\"Powerbeats3\",\"0520\",\"BeatsX\",\"0620\",\"Beats Solo3\"]},\"color\":{\"decoder\":[\"static_value\",\"thus far unknown - please report your color\"]},\"_color\":{\"decoder\":[\"string_from_hex_data\",\"manufacturerdata\",22,2],\"lookup\":[\"00\",\"white\",\"01\",\"black\",\"02\",\"red\",\"03\",\"blue\",\"04\",\"pink\",\"05\",\"gray\",\"06\",\"silver\",\"07\",\"gold\",\"08\",\"rose gold\",\"09\",\"space gray\",\"0a\",\"dark blue\",\"0b\",\"light blue\",\"0c\",\"yellow\"]},\"status\":{\"decoder\":[\"static_value\",\"thus far unknown - please report your status\"]},\"_status\":{\"decoder\":[\"string_from_hex_data\",\"manufacturerdata\",15,1],\"lookup\":[\"5\",\"Both AirPods in case\",\"1\",\"Both AirPods out of case\",\"3\",\"Both AirPods in ears\"]},\"batt_r\":{\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",16,1],\"post_proc\":[\"*\",10,\"max\",100]},\"batt_l\":{\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",17,1],\"post_proc\":[\"*\",10,\"max\",100]},\"batt_case\":{\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",19,1],\"post_proc\":[\"*\",10,\"max\",100]},\"lid_open\":{\"decoder\":[\"value_from_hex_data\",\"manufacturerdata\",20,2,false,false]},\"charging_r\":{\"decoder\":[\"bit_static_value\",\"manufacturerdata\",18,1,false,true]},\"charging_l\":{\"decoder\":[\"bit_static_value\",\"manufacturerdata\",18,0,false,true]},\"charging_case\":{\"decoder\":[\"bit_static_value\",\"manufacturerdata\",18,2,false,true]}}}";
/*R""""(
{
"brand":"Apple/Beats",
"model":"AirPods (Pro)/Solo|Studio Buds",
"model_id":"APPLEAIRPODS",
"tag":"1208",
"condition":["manufacturerdata", "index", 8, "01", "&", "manufacturerdata","=", 58, "index", 0, "4c0007"],
"properties":{
"version":{
"decoder":["static_value", "thus far unknown - please report your model version"]
},
"_version":{
"decoder":["string_from_hex_data", "manufacturerdata", 10, 4],
"lookup":["0220", "AirPods 1st gen.",
"0e20", "AirPods Pro 1st gen.",
"1420", "AirPods Pro 2nd gen.",
"0320", "Powerbeats3",
"0520", "BeatsX",
"0620", "Beats Solo3"]
},
"color":{
"decoder":["static_value", "thus far unknown - please report your color"]
},
"_color":{
"decoder":["string_from_hex_data", "manufacturerdata", 22, 2],
"lookup":["00", "white",
"01", "black",
"02", "red",
"03", "blue",
"04", "pink",
"05", "gray",
"06", "silver",
"07", "gold",
"08", "rose gold",
"09", "space gray",
"0a", "dark blue",
"0b", "light blue",
"0c", "yellow"]
},
"status":{
"decoder":["static_value", "thus far unknown - please report your status"]
},
"_status":{
"decoder":["string_from_hex_data", "manufacturerdata", 15, 1],
"lookup":["5", "Both AirPods in case",
"1", "Both AirPods out of case",
"3", "Both AirPods in ears"]
},
"batt_r":{
"decoder":["value_from_hex_data", "manufacturerdata", 16, 1],
"post_proc":["*", 10, "max", 100]
},
"batt_l":{
"decoder":["value_from_hex_data", "manufacturerdata", 17, 1],
"post_proc":["*", 10, "max", 100]
},
"batt_case":{
"decoder":["value_from_hex_data", "manufacturerdata", 19, 1],
"post_proc":["*", 10, "max", 100]
},
"lid_open":{
"decoder":["value_from_hex_data", "manufacturerdata", 20, 2, false, false]
},
"charging_r":{
"decoder":["bit_static_value", "manufacturerdata", 18, 1, false, true]
},
"charging_l":{
"decoder":["bit_static_value", "manufacturerdata", 18, 0, false, true]
},
"charging_case":{
"decoder":["bit_static_value", "manufacturerdata", 18, 2, false, true]
}
}
})"""";*/

const char* _APPLEAIRPODS_json_props = "{\"properties\":{\"version\":{\"unit\":\"string\",\"name\":\"model version\"},\"color\":{\"unit\":\"string\",\"name\":\"color\"},\"status\":{\"unit\":\"string\",\"name\":\"status\"},\"batt_r\":{\"unit\":\"%\",\"name\":\"batt\"},\"batt_l\":{\"unit\":\"%\",\"name\":\"batt\"},\"batt_case\":{\"unit\":\"%\",\"name\":\"batt\"},\"lid_open\":{\"unit\":\"int\",\"name\":\"lid open counter\"},\"charging_r\":{\"unit\":\"status\",\"name\":\"battery_charging\"},\"charging_l\":{\"unit\":\"status\",\"name\":\"battery_charging\"},\"charging_case\":{\"unit\":\"status\",\"name\":\"battery_charging\"}}}";
/*R""""(
{
"properties":{
"version":{
"unit":"string",
"name":"model version"
},
"color":{
"unit":"string",
"name":"color"
},
"status":{
"unit":"string",
"name":"status"
},
"batt_r":{
"unit":"%",
"name":"batt"
},
"batt_l":{
"unit":"%",
"name":"batt"
},
"batt_case":{
"unit":"%",
"name":"batt"
},
"lid_open":{
"unit":"int",
"name":"lid open counter"
},
"charging_r":{
"unit":"status",
"name":"battery_charging"
},
"charging_l":{
"unit":"status",
"name":"battery_charging"
},
"charging_case":{
"unit":"status",
"name":"battery_charging"
}
}
})"""";*/
39 changes: 36 additions & 3 deletions tests/BLE/test_ble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ const char* expected_mfg[] = {
"{\"brand\":\"Apple\",\"model\":\"Apple Continuity\",\"model_id\":\"APPLE_CONT\",\"type\":\"RMAC\",\"device\":\"Apple device\"}",
"{\"brand\":\"Apple\",\"model\":\"Apple Continuity\",\"model_id\":\"APPLE_CONTAT\",\"type\":\"RMAC\",\"device\":\"Apple device\"}",
"{\"brand\":\"Apple\",\"model\":\"Apple Continuity\",\"model_id\":\"APPLE_CONTAT\",\"type\":\"RMAC\",\"device\":\"Apple device\"}",
"{\"brand\":\"Apple\",\"model\":\"Apple Continuity\",\"model_id\":\"APPLE_CONTAT\",\"type\":\"RMAC\",\"device\":\"Apple device\"}",
"{\"brand\":\"iTAG\",\"model\":\"Smart Tracker\",\"model_id\":\"ITAG\",\"type\":\"TRACK\",\"cidc\":false,\"acts\":true,\"track\":true,\"device\":\"iTAG Tracker\"}",
"{\"brand\":\"Tile\",\"model\":\"Smart Tracker\",\"model_id\":\"TILE\",\"type\":\"TRACK\",\"cidc\":false,\"acts\":true,\"track\":true,\"device\":\"Tile Tracker\"}",
"{\"brand\":\"Govee\",\"model\":\"Smart Air Quality Monitor\",\"model_id\":\"H5106\",\"type\":\"AIR\",\"cidc\":false,\"acts\":true,\"tempc\":22.7,\"tempf\":72.86,\"hum\":63.1,\"pm25\":2}",
Expand Down Expand Up @@ -168,6 +167,18 @@ const char* expected_mfg[] = {
"{\"brand\":\"Onset\",\"model\":\"Hobo Water Level Sensor\",\"model_id\":\"HOBOMX2001\",\"type\":\"UNIQ\",\"lvl_cm\":8.46760273,\"lvl_in\":3.333701862}",
"{\"brand\":\"Onset\",\"model\":\"Hobo Water Level Sensor\",\"model_id\":\"HOBOMX2001\",\"type\":\"UNIQ\",\"lvl_cm\":9.514185786,\"lvl_in\":3.745742436}",
"{\"brand\":\"SwitchBot\",\"model\":\"Outdoor Meter\",\"model_id\":\"W340001X\",\"type\":\"THB\",\"tempc\":25.5,\"tempf\":77.9,\"hum\":50,\"mac\":\"AA:BB:CC:DD:EE:FF\"}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 1st gen.\",\"color\":\"white\",\"status\":\"thus far unknown - please report your status\",\"batt_r\":100,\"batt_l\":50,\"batt_case\":100,\"lid_open\":0,\"charging_r\":false,\"charging_l\":false,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 1st gen.\",\"color\":\"white\",\"status\":\"thus far unknown - please report your status\",\"batt_r\":100,\"batt_l\":90,\"batt_case\":100,\"lid_open\":0,\"charging_r\":false,\"charging_l\":false,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods out of case\",\"batt_r\":100,\"batt_l\":100,\"batt_case\":30,\"lid_open\":17,\"charging_r\":true,\"charging_l\":false,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods in case\",\"batt_r\":100,\"batt_l\":100,\"batt_case\":30,\"lid_open\":50,\"charging_r\":true,\"charging_l\":true,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods out of case\",\"batt_r\":100,\"batt_l\":100,\"batt_case\":30,\"lid_open\":18,\"charging_r\":true,\"charging_l\":false,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods out of case\",\"batt_r\":100,\"batt_l\":100,\"batt_case\":100,\"lid_open\":18,\"charging_r\":false,\"charging_l\":false,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods out of case\",\"batt_r\":90,\"batt_l\":90,\"batt_case\":70,\"lid_open\":50,\"charging_r\":false,\"charging_l\":true,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods out of case\",\"batt_r\":100,\"batt_l\":90,\"batt_case\":70,\"lid_open\":17,\"charging_r\":true,\"charging_l\":false,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods in case\",\"batt_r\":100,\"batt_l\":90,\"batt_case\":70,\"lid_open\":50,\"charging_r\":true,\"charging_l\":true,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods in case\",\"batt_r\":90,\"batt_l\":90,\"batt_case\":70,\"lid_open\":81,\"charging_r\":true,\"charging_l\":true,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods in case\",\"batt_r\":90,\"batt_l\":90,\"batt_case\":60,\"lid_open\":81,\"charging_r\":true,\"charging_l\":true,\"charging_case\":false}",
"{\"brand\":\"Apple/Beats\",\"model\":\"AirPods (Pro)/Solo|Studio Buds\",\"model_id\":\"APPLEAIRPODS\",\"type\":\"AUDIO\",\"track\":true,\"version\":\"AirPods Pro 2nd gen.\",\"color\":\"white\",\"status\":\"Both AirPods in ears\",\"batt_r\":80,\"batt_l\":90,\"batt_case\":100,\"lid_open\":16,\"charging_r\":false,\"charging_l\":false,\"charging_case\":false}",
};

const char* expected_name_uuid_mfgsvcdata[] = {
Expand Down Expand Up @@ -604,7 +615,6 @@ const char* test_mfgdata[][3] = {
{"Apple", "Continuity", "4c0009060304c0a87b1e130c1adefc915b9ef8010401030c"},
{"Apple", "Continuity", "4c00130100"},
{"Apple", "Continuity", "4c001219003d9967e0d67bf55617939043e48fd6762144da3e35160300"},
{"Apple", "Continuity", "4c000719010e2022f58f00000a7d9fff27234873d4305e0fed1b39e2b8"},
{"Apple", "Continuity", "4c000c0e00a7582cd64fff2fe83046c99f5b10065a19e96670d8"},
{"Tracker iTAG", "iTAG", "8afc23eb"},
{"Tile name", "Tile", "xxxx"},
Expand Down Expand Up @@ -666,6 +676,18 @@ const char* test_mfgdata[][3] = {
{"Hobo Water Level", "", "c500073fd54f0106240000000800529501a0a06aad3d"},
{"Hobo Water Level", "", "c500073fd54f010624000000080092a901a0bcd9c23d"},
{"SwitchBot Outdoor Meter Manufacturerdata", "WoIOSensorTH", "6909aabbccddeeff8b0305993200"},
{"Apple", "AirPods", "4c000719010e2022f58f00000a7d9fff27234873d4305e0fed1b39e2b8"},
{"Apple", "AirPods", "4c000719010e2002f98f0000058de7929a3aa09ed6fbb010db935b056c"},
{"Apple", "AirPods", "4c00071901142011aaa3110004254f0c5375c903064e61be2590411d53"},
{"Apple", "AirPods", "4c00071901142075aab3320004336834816d0f667558352a4e211589aa"},
{"Apple", "AirPods", "4c00071901142031aaa3120004a1156f4a5481160b323df3f8d892bfc8"},
{"Apple", "AirPods", "4c00071901142021aa8f12000471436c43b098ff4365eb784afd30c09e"},
{"Apple", "AirPods", "4c0007190114207199973200080c1b53c3031aa10c5da3847e3690f7db"},
{"Apple", "AirPods", "4c00071901142031a9a7110004e9d97f8a064c7f4fcc0df5e7aa48708f"},
{"Apple", "AirPods", "4c00071901142075a9b732000882b97530ec03edd806dced9d00e6a14f"},
{"Apple", "AirPods", "4c0007190114203599b751000444a7139966d773e3e1b642a3be823d75"},
{"Apple", "AirPods", "4c0007190114205599b65100082b939c385b205372f32501b289b844a8"},
{"Apple", "AirPods", "4c00071901142003898f100008cc74d502b12d6d72e0f4f6eabf826972"},
};

TheengsDecoder::BLE_ID_NUM test_mfgdata_id_num[]{
Expand Down Expand Up @@ -756,7 +778,6 @@ TheengsDecoder::BLE_ID_NUM test_mfgdata_id_num[]{
TheengsDecoder::BLE_ID_NUM::APPLE_CONT,
TheengsDecoder::BLE_ID_NUM::APPLE_CONTAT,
TheengsDecoder::BLE_ID_NUM::APPLE_CONTAT,
TheengsDecoder::BLE_ID_NUM::APPLE_CONTAT,
TheengsDecoder::BLE_ID_NUM::ITAG,
TheengsDecoder::BLE_ID_NUM::TILEN,
TheengsDecoder::BLE_ID_NUM::H5106,
Expand Down Expand Up @@ -817,6 +838,18 @@ TheengsDecoder::BLE_ID_NUM test_mfgdata_id_num[]{
TheengsDecoder::BLE_ID_NUM::HOBOMX2001,
TheengsDecoder::BLE_ID_NUM::HOBOMX2001,
TheengsDecoder::BLE_ID_NUM::SBOT_M,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
TheengsDecoder::BLE_ID_NUM::APPLEAIRPODS,
};

// uuid test input [test name] [device name] [uuid] [manufacturer data] [service data]
Expand Down

0 comments on commit d6974eb

Please sign in to comment.