Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support to Beewi Smart Door as broadcaster. #22

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ is published.
* `TLM` frames: `Voltage`, `Temperature`, `Count` and `Uptime`
* For MiJia temperature and humidity sensors: `MACAddress`, `MessageCounter`,
`Temperature`, `Humidity` and `BatteryLevel`

* For BeeWi Smart Door sensors: `Status` (opening door state) and `Battery`

**Note:** Broadcaster topics are published without the retained flag regardless
of what's defined in the configuration file.

Expand Down
79 changes: 78 additions & 1 deletion main/broadcasters.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ static void mijia_temp_hum_metadata_get(uint8_t *adv_data, size_t adv_data_len,
uint8_t len;
mijia_temp_hum_t *mijia_temp_hum = mijia_temp_hum_data_get(adv_data,
adv_data_len, &len);

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be a part of this commit.

cb("MACAddress", _mactoa(mijia_temp_hum->mac), ctx);
sprintf(s, "%hhu", mijia_temp_hum->message_counter);
cb("MessageCounter", s, ctx);
Expand Down Expand Up @@ -389,12 +389,89 @@ static broadcaster_ops_t mijia_temp_hum_ops = {
.is_broadcaster = mijia_temp_hum_is_broadcaster,
.metadata_get = mijia_temp_hum_metadata_get,
};
/* Beewi Smart Door */
#define BEEWI_SMART_DOOR_COMPANY_ID 0x000D
#define BEEWI_SMART_DOOR_SERVICE_ID 0x08
#define BEEWI_SMART_DOOR_DATA_TBD1 0x0C
#define BEEWI_SMART_DOOR_DATA_TBD2 0x06 //unused here


typedef struct {
uint16_t company_id;
uint8_t service_id;
uint8_t tbd1;
uint8_t status;
uint8_t tbd2;
uint8_t battery;
} __attribute__((packed)) beewi_smart_door_t;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is the exact format of the payload?
Could it be that the status and battery fields may either be included or not and according to the type field you should check?
Do you have any documentation you can share regarding the advertisement payload?

Copy link
Contributor Author

@KipK KipK Jan 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No doc at all they refused to communicate specs. This is just reverse enginering.
Status and Batt are always present in this frame.

Here is a complete packet :
02 01 06 02 0A 00 08 FF 0D 00 08 0C 01 06 64 11 09 42 65 57 69 20 53 6D 61 72 74 20 44 6F 6F 72 => Open
02 01 06 02 0A 00 08 FF 0D 00 08 0C 00 06 64 11 09 42 65 57 69 20 53 6D 61 72 74 20 44 6F 6F 72 => Closed

As there's always 0C before Status and 06 before Battery I've defined them as identifier.
0D 00 part before is the Company ID ( not from the device but from the bt chipset i to the standard, Texas Instrument here ( 00 0D ) .
Here is complete wireshark analysis of the packet :

Frame 435: 44 bytes on wire (352 bits), 44 bytes captured (352 bits)
Encapsulation type: Bluetooth H4 with linux header (99)
Arrival Time: Jan 22, 2019 11:33:07.735169000 Paris, Madrid
[Time shift for this packet: 0.000000000 seconds]
Epoch Time: 1548153187.735169000 seconds
[Time delta from previous captured frame: 0.259482000 seconds]
[Time delta from previous displayed frame: 0.259482000 seconds]
[Time since reference or first frame: 41.804692000 seconds]
Frame Number: 435
Frame Length: 44 bytes (352 bits)
Capture Length: 44 bytes (352 bits)
[Frame is marked: False]
[Frame is ignored: False]
Point-to-Point Direction: Received (1)
[Protocols in frame: bluetooth:hci_h4:bthci_evt:btcommon]
Bluetooth
[Source: controller]
[Destination: host]
Bluetooth HCI H4
[Direction: Rcvd (0x01)]
HCI Packet Type: HCI Event (0x04)
Bluetooth HCI Event - LE Meta
Event Code: LE Meta (0x3e)
Parameter Total Length: 41
Sub Event: LE Extended Advertising Report (0x0d)
Num Reports: 1
Event Type: 0x0013, Connectable, Scannable, Legacy, Data Status: Complete
Peer Address Type: Public Device Address (0x00)
BD_ADDR: TexasIns_e3:a4:e6 (10:ce:a9:e3:a4:e6)
Primary PHY: LE 1M (0x01)
Secondary PHY: No packets on the secondary advertising channel (0x00)
Advertising SID: 0xff (not available)
TX Power: 127dBm (not available)
RSSI: -65dBm
Periodic Advertising Interval: 0x0000 (no periodic advertising)
Direct Address Type: Public Device Address (0x00)
Direct BD_ADDR: 00:00:00_00:00:00 (00:00:00:00:00:00)
Data Length: 15
Advertising Data
Flags
Length: 2
Type: Flags (0x01)
000. .... = Reserved: 0x0
...0 .... = Simultaneous LE and BR/EDR to Same Device Capable (Host): false (0x0)
.... 0... = Simultaneous LE and BR/EDR to Same Device Capable (Controller): false (0x0)
.... .1.. = BR/EDR Not Supported: true (0x1)
.... ..1. = LE General Discoverable Mode: true (0x1)
.... ...0 = LE Limited Discoverable Mode: false (0x0)
Tx Power Level
Length: 2
Type: Tx Power Level (0x0a)
Power Level (dBm): 0
Manufacturer Specific
Length: 8
Type: Manufacturer Specific (0xff)
Company ID: Texas Instruments Inc. (0x000d)
Data: 080c010664
[Expert Info (Note/Undecoded): Undecoded]
[Undecoded]
[Severity level: Note]
[Group: Undecoded]

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, in that case, using the company ID to distinguish these devices isn't good enough.
I suggest you try to read the ESP_BLE_AD_TYPE_NAME_CMPL part of the advertisement data and compare it with BeWi Smart Door.
That should be specific enough. I would also suggest marking the type_stat and type_batt fields as tbd1 and tbd2 as we don't really know yet what they are.
Since we know for sure this is the smart door sensor (as we read its name), we can forgo checking these stat fields and just assume the values are where we expect them to be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll compare with advertised device name. That's what I'm already doing in another project.
But we also nee to check the type_stat as device broadcast another frame starting also with 00 D0 08 when in pairing mode. Couldn't figure what data there's in. Probably only an identifier string to say it's in pairing state.

Copy link
Contributor Author

@KipK KipK Jan 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying this but it doesn't seems to work :

snprintf(dev_name, strlen(dev_name), "%s", esp_ble_resolve_adv_data(adv_data, ESP_BLE_AD_TYPE_NAME_CMPL, &dev_len ));
if (strncmp(dev_name, "Beewi Smart Door", dev_len) == 0)
return 1;
else return 0;

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's probably because the device sends BeWi Smart Door and not BeeWi Smart Door.
Also, esp_ble_resolve_adv_data() might return NULL so watch out for that. Since you're using strncmp() anyways, there really is no need to put it in a buffer first.


static beewi_smart_door_t *beewi_smart_door_data_get(uint8_t *adv_data,
uint8_t adv_data_len, uint8_t *beewi_smart_door_len)
{
uint8_t len;
uint8_t *data = esp_ble_resolve_adv_data(adv_data,
ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE, &len);

if (beewi_smart_door_len)
*beewi_smart_door_len = len;

return (beewi_smart_door_t *)data;
}

static int beewi_smart_door_is_broadcaster(uint8_t *adv_data,
size_t adv_data_len)
{
uint8_t name_len;
char *name = (char *)esp_ble_resolve_adv_data(adv_data,
ESP_BLE_AD_TYPE_NAME_CMPL, &name_len);
if (strncmp(name, "BeeWi Smart Door", name_len) != 0)
return 0
;

uint8_t len;
beewi_smart_door_t *beewi_smart_door = beewi_smart_door_data_get(adv_data,
adv_data_len, &len);

/* Technically, we should also prevent connecting to the device, as it stops broadcasting
then. Or just once to get device name, and other static infos. Interesting data as opening status & battery are broadcasted.
Battery data is also available as characteristic, but not the essential data, the door status.
Needs to blacklist the mac in service config to make this working*/


if (!beewi_smart_door || len != sizeof(beewi_smart_door_t))
return 0;

else return 1;

}

static void beewi_smart_door_metadata_get(uint8_t *adv_data,
size_t adv_data_len, int rssi, broadcaster_meta_data_cb_t cb, void *ctx)
{
char s[6];
beewi_smart_door_t *beewi_smart_door = beewi_smart_door_data_get(adv_data,
adv_data_len, NULL);

if (beewi_smart_door->tbd1 == BEEWI_SMART_DOOR_DATA_TBD1) {
sprintf(s,"%hhu",beewi_smart_door->status );
cb("Status", s, ctx);
sprintf(s,"%hhu",beewi_smart_door->battery);
cb("Battery", s, ctx);
}
}

static broadcaster_ops_t beewi_smart_door_ops = {
.name = "BeeWi Smart Door",
.is_broadcaster = beewi_smart_door_is_broadcaster,
.metadata_get = beewi_smart_door_metadata_get,
};

/* Common */
static broadcaster_ops_t *broadcaster_ops[] = {
&ibeacon_ops,
&eddystone_ops,
&mijia_temp_hum_ops,
&beewi_smart_door_ops,
NULL
};

Expand Down
2 changes: 1 addition & 1 deletion main/broadcasters.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <stddef.h>
#include <stdint.h>

#define MAX_BROADCASTER_NAME 16
#define MAX_BROADCASTER_NAME 17

/* Event callback types */
typedef void (*broadcaster_meta_data_cb_t)(char *name, char *val, void *ctx);
Expand Down