- Bramka w trybie parowania (180 sekund od resetu albo 1x BOOT),
- urządzenie Zigbee wprowadzone w tryb parowania łączy się z siecią Zigbee utworzoną przez bramkę,
- bramka odpytuje urządzenie Zigbee o nazwę producenta i model - jeżeli rozpozna urządzenie na podstawie wpisu w bazie to wykonuje następujace kroki:
- wykonuje tzw. binding na wybranych klastrach,
- generuje kanał/kanały Supla odpowiadające urządzeniu Zigbee, np. DoorSensor -> Supla::Sensor::VirtualBinary,
- wiele urządzeń Zigbee wygeneruje kilka kanałów Supla, np. takie gniazdko z pomiarem energii -> przekaźnik + licznik energii elektrycznej.
Opis modelu działania bramki Z2S
Moderator: vajera
-
vajera
- Posts: 7290
- Joined: Wed Oct 31, 2018 7:58 am
- Location: Biedrusko
- Has thanked: 289 times
- Been thanked: 161 times
Bramka Zigbee <=> SUPLA
Więcej informacji tutaj:
https://forum.supla.org/viewforum.php?f=127
FAQ https://forum.supla.org/viewtopic.php?t=17277
Więcej informacji tutaj:
https://forum.supla.org/viewforum.php?f=127
FAQ https://forum.supla.org/viewtopic.php?t=17277
-
vajera
- Posts: 7290
- Joined: Wed Oct 31, 2018 7:58 am
- Location: Biedrusko
- Has thanked: 289 times
- Been thanked: 161 times
Chciałem podzielić się z Wami przykładem tego, jak identyczna funkcjonalność potrafi różnić się skalą implementacji w przypadku różnych urządzeń Zigbee:
przykład dotyczy trzech głowic TRV, które pozwalają na bezpośrednie przesyłanie temperatury do głowicy (bez użycia kalibracji temperatury, wysyłana jest rzeczywista wartość pomiaru).
Głowica Bosch BTH-RA:
Głowica Sonoff TRV-ZB:
i teraz gwiazda wieczoru
Aqara E1 (kod podzieliłem na 4 części):
przykład dotyczy trzech głowic TRV, które pozwalają na bezpośrednie przesyłanie temperatury do głowicy (bez użycia kalibracji temperatury, wysyłana jest rzeczywista wartość pomiaru).
Głowica Bosch BTH-RA:
Code: Select all
_gateway->sendAttributeWrite(
&_device,
ESP_ZB_ZCL_CLUSTER_ID_THERMOSTAT,
BOSCH_TRV_EXTERNAL_TEMPERATURE_INPUT_ID,
ESP_ZB_ZCL_ATTR_TYPE_S16,
2, &external_sensor_temperature,
true,
1, BOSCH_MANUFACTURER_CODE);
Code: Select all
_gateway->sendAttributeWrite(
&_device,
SONOFF_CUSTOM_CLUSTER,
TRVZB_CMD_SET_TEMPERATURE_SENSOR_SELECT,
ESP_ZB_ZCL_ATTR_TYPE_U8, 1, &temperature_selector);
_gateway->sendAttributeWrite(
&_device,
SONOFF_CUSTOM_CLUSTER,
TRVZB_CMD_SET_EXTERNAL_TEMPERATURE_INPUT,
ESP_ZB_ZCL_ATTR_TYPE_S16, 2, &external_sensor_temperature);
Code: Select all
typedef struct lumi_fff2_cmd_header_s {
uint8_t cmd_start;
uint8_t cmd_category;
uint8_t cmd_size;
uint8_t cmd_type;
uint8_t counter;
uint8_t integrity;
uint8_t cmd_action;
uint8_t data_type;
uint8_t params_size;
} __attribute__((packed)) lumi_fff2_cmd_header_t;
typedef struct lumi_sensor_link_params_1_s {
uint32_t timestamp;
uint8_t const_value_3d;
uint8_t link_id;
esp_zb_ieee_addr_t device_address;
esp_zb_ieee_addr_t sensor_address;
uint8_t shared_const_value[4];
uint8_t const_value_link_1[11];
uint8_t const_common_value[7];
uint8_t const_value_64;
uint8_t const_end_65;
} __attribute__((packed)) lumi_sensor_link_params_1_t;
typedef struct lumi_sensor_link_params_2_s {
uint32_t timestamp;
uint8_t const_value_3d;
uint8_t link_id;
esp_zb_ieee_addr_t device_address;
esp_zb_ieee_addr_t sensor_address;
uint8_t const_value_link_2[18];
uint8_t const_common_value[7];
uint8_t const_value_04;
uint8_t const_end_65;
} __attribute__((packed)) lumi_sensor_link_params_2_t;
typedef struct lumi_sensor_unlink_params_s {
uint32_t timestamp;
uint8_t const_value_3d;
uint8_t link_id;
esp_zb_ieee_addr_t device_address;
uint8_t sensor_address[12];
} __attribute__((packed)) lumi_sensor_unlink_params_t;
typedef struct lumi_sensor_send_temperature_params_s {
esp_zb_ieee_addr_t sensor_address;
uint8_t const_value[4];
float temperature_100;
} __attribute__((packed)) lumi_sensor_send_temperature_params_t;
static constexpr lumi_fff2_cmd_header_t
lumi_fff2_cmd_header_template PROGMEM = {
.cmd_start = 0xAA,
.cmd_category = 0x71,
.cmd_size = 0x31,
.cmd_type = 0x44,
.counter = 0x10,
.integrity = 0x60, //512 - sum(cmd_start..counter)
.cmd_action = 0x02,
.data_type = 0x41,
.params_size = 0x2E
};
static constexpr lumi_sensor_link_params_1_t
lumi_sensor_link_params_1_template PROGMEM = {
.timestamp = 0x00000000,
.const_value_3d = 0x3D,
.link_id = 04,
.device_address = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
.sensor_address = { 0x00, 0x15, 0x8D, 0x00, 0x01, 0x9D, 0x1B, 0x98 },//some static value - seems enough
.shared_const_value = { 0x00, 0x01, 0x00, 0x55 },
.const_value_link_1 = { 0x13, 0x0A, 0x02, 0x00, 0x00, 0x64,
0x04, 0xCE, 0xC2, 0xB6, 0xC8 },
.const_common_value = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3D },
.const_value_64 = 0x64,
.const_end_65 = 0x65,
};
static constexpr lumi_sensor_link_params_2_t
lumi_sensor_link_params_2_template PROGMEM = {
.timestamp = 0x00000000,
.const_value_3d = 0x3D,
.link_id = 05,
.device_address = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.sensor_address = { 0x00, 0x15, 0x8D, 0x00, 0x01, 0x9D, 0x1B, 0x98 },//some static value - seems enough
.const_value_link_2 = {0x08, 0x00, 0x07, 0xFD, 0x16, 0x0A, 0x02, 0x0A, 0xC9,
0xE8, 0xB1, 0xB8, 0xD4, 0xDA, 0xCF, 0xDF, 0xC0, 0xEB},
.const_common_value = {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3D},
.const_value_04 = 0x04,
.const_end_65 = 0x65,
};
static constexpr lumi_sensor_unlink_params_t
lumi_sensor_unlink_params_template PROGMEM = {
.timestamp = 0x00000000,
.const_value_3d = 0x3D,
.link_id = 05,
.device_address = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.sensor_address = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0}
};
static constexpr lumi_sensor_unlink_params_t
lumi_sensor_unlink_params_2 PROGMEM = {
.timestamp = 0x00000000,
.const_value_3d = 0x3D,
.link_id = 04,
.device_address = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.sensor_address = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0}
};
static constexpr lumi_sensor_send_temperature_params_t
lumi_sensor_send_temperature_params_template PROGMEM = {
.sensor_address = { 0x00, 0x15, 0x8D, 0x00, 0x01, 0x9D, 0x1B, 0x98 },//some static value - seems enough
.const_value = {0x00, 0x01, 0x00, 0x55},
.temperature_100 = -27500
};
Code: Select all
void buildLumiFFF2CmdHeader(uint8_t* fff2_cmd_data_buffer,
uint8_t counter,
uint8_t action,
uint8_t params_size) {
memset(fff2_cmd_data_buffer, 0 , 0xAA);
uint8_t fff2_header_size = sizeof(lumi_fff2_cmd_header_t);
memcpy(fff2_cmd_data_buffer,
&lumi_fff2_cmd_header_template,
fff2_header_size);
lumi_fff2_cmd_header_t *lumi_fff2_cmd_header =
(lumi_fff2_cmd_header_t *)fff2_cmd_data_buffer;
lumi_fff2_cmd_header->cmd_size = params_size + 3;
lumi_fff2_cmd_header->counter = counter;
lumi_fff2_cmd_header->cmd_action = action;
lumi_fff2_cmd_header->params_size = params_size;
uint16_t integrity = lumi_fff2_cmd_header->cmd_start +
lumi_fff2_cmd_header->cmd_category +
lumi_fff2_cmd_header->cmd_size +
lumi_fff2_cmd_header->cmd_type +
lumi_fff2_cmd_header->counter;
integrity = 512 - integrity;
lumi_fff2_cmd_header->integrity = integrity;
}
uint8_t buildLumiFFF2CmdLinkParams1(uint8_t* fff2_cmd_data_buffer,
uint8_t counter,
time_t timestamp,
esp_zb_ieee_addr_t ieee_addr) {
uint8_t fff2_header_size = sizeof(lumi_fff2_cmd_header_t);
uint8_t lumi_sensor_link_params_1_size =
sizeof(lumi_sensor_link_params_1_t);
*fff2_cmd_data_buffer = fff2_header_size + lumi_sensor_link_params_1_size;
buildLumiFFF2CmdHeader(fff2_cmd_data_buffer + 1,
counter,
LUMI_FFF2_CMD_ACTION_LINK_SENSOR,
lumi_sensor_link_params_1_size);
memcpy(fff2_cmd_data_buffer + fff2_header_size + 1,
&lumi_sensor_link_params_1_template,
lumi_sensor_link_params_1_size);
lumi_sensor_link_params_1_t *lumi_sensor_link_params_1 =
(lumi_sensor_link_params_1_t*)(fff2_cmd_data_buffer + fff2_header_size + 1);
lumi_sensor_link_params_1->timestamp = timestamp;
/*memcpy(lumi_sensor_link_params_1->device_address,
ieee_addr,
sizeof(esp_zb_ieee_addr_t));
*/
for (uint8_t i = 0; i < sizeof(esp_zb_ieee_addr_t); i++)
lumi_sensor_link_params_1->device_address[i] = ieee_addr[7 - i];
return fff2_header_size + lumi_sensor_link_params_1_size + 1;
}
uint8_t buildLumiFFF2CmdLinkParams2(uint8_t* fff2_cmd_data_buffer,
uint8_t counter,
time_t timestamp,
esp_zb_ieee_addr_t ieee_addr) {
uint8_t fff2_header_size = sizeof(lumi_fff2_cmd_header_t);
uint8_t lumi_sensor_link_params_2_size =
sizeof(lumi_sensor_link_params_2_t);
*fff2_cmd_data_buffer = fff2_header_size + lumi_sensor_link_params_2_size;
buildLumiFFF2CmdHeader(fff2_cmd_data_buffer + 1,
counter,
LUMI_FFF2_CMD_ACTION_LINK_SENSOR,
lumi_sensor_link_params_2_size);
memcpy(fff2_cmd_data_buffer + fff2_header_size + 1,
&lumi_sensor_link_params_2_template,
lumi_sensor_link_params_2_size);
lumi_sensor_link_params_2_t *lumi_sensor_link_params_2 =
(lumi_sensor_link_params_2_t*)(fff2_cmd_data_buffer + fff2_header_size + 1);
lumi_sensor_link_params_2->timestamp = timestamp;
/*memcpy(lumi_sensor_link_params_2->device_address,
ieee_addr,
sizeof(esp_zb_ieee_addr_t));*/
for (uint8_t i = 0; i < sizeof(esp_zb_ieee_addr_t); i++)
lumi_sensor_link_params_2->device_address[i] = ieee_addr[7 - i];
return fff2_header_size + lumi_sensor_link_params_2_size + 1;
}
uint8_t buildLumiFFF2CmdUnlinkParams(uint8_t* fff2_cmd_data_buffer,
uint8_t counter,
time_t timestamp,
uint8_t link_id,
esp_zb_ieee_addr_t ieee_addr) {
uint8_t fff2_header_size = sizeof(lumi_fff2_cmd_header_t);
uint8_t lumi_sensor_unlink_params_size =
sizeof(lumi_sensor_unlink_params_t);
*fff2_cmd_data_buffer = fff2_header_size + lumi_sensor_unlink_params_size;
buildLumiFFF2CmdHeader(fff2_cmd_data_buffer + 1,
counter,
LUMI_FFF2_CMD_ACTION_UNLINK_SENSOR,
lumi_sensor_unlink_params_size);
memcpy(fff2_cmd_data_buffer + fff2_header_size + 1,
&lumi_sensor_unlink_params_template,
lumi_sensor_unlink_params_size);
lumi_sensor_unlink_params_t *lumi_sensor_unlink_params =
(lumi_sensor_unlink_params_t*)(fff2_cmd_data_buffer + fff2_header_size + 1);
lumi_sensor_unlink_params->timestamp = timestamp;
lumi_sensor_unlink_params->link_id = link_id;
/*memcpy(lumi_sensor_unlink_params->device_address,
ieee_addr,
sizeof(esp_zb_ieee_addr_t));*/
for (uint8_t i = 0; i < sizeof(esp_zb_ieee_addr_t); i++)
lumi_sensor_unlink_params->device_address[i] = ieee_addr[7 - i];
return fff2_header_size + lumi_sensor_unlink_params_size + 1;
}
float ReverseFloat( const float inFloat ) {
float retVal;
char *floatToConvert = ( char* ) & inFloat;
char *returnFloat = ( char* ) & retVal;
// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[3];
returnFloat[1] = floatToConvert[2];
returnFloat[2] = floatToConvert[1];
returnFloat[3] = floatToConvert[0];
return retVal;
}
uint8_t buildLumiFFF2CmdSendTemperatureParams(uint8_t* fff2_cmd_data_buffer,
float temperature_100) {
uint8_t fff2_header_size = sizeof(lumi_fff2_cmd_header_t);
uint8_t lumi_sensor_send_temperature_params_size =
sizeof(lumi_sensor_send_temperature_params_t);
*fff2_cmd_data_buffer = fff2_header_size + lumi_sensor_send_temperature_params_size;
buildLumiFFF2CmdHeader(fff2_cmd_data_buffer + 1,
0x10,
LUMI_FFF2_CMD_ACTION_SEND_TEMPERATURE,
lumi_sensor_send_temperature_params_size);
memcpy(fff2_cmd_data_buffer + fff2_header_size + 1,
&lumi_sensor_send_temperature_params_template,
lumi_sensor_send_temperature_params_size);
lumi_sensor_send_temperature_params_t *lumi_sensor_send_temperature_params =
(lumi_sensor_send_temperature_params_t*)(fff2_cmd_data_buffer +
fff2_header_size + 1);
lumi_sensor_send_temperature_params->temperature_100 =
ReverseFloat(temperature_100);
return fff2_header_size + lumi_sensor_send_temperature_params_size + 1;
}
Code: Select all
uint8_t fff2_cmd_data_buffer[0xAA];
time_t timestamp = time(nullptr);
if (trv_external_sensor_present) {
uint8_t buffer_size =
buildLumiFFF2CmdLinkParams1(fff2_cmd_data_buffer,
0x12,
timestamp,
_device.ieee_addr);
_gateway->sendAttributeWrite(
&_device,
LUMI_CUSTOM_CLUSTER,
LUMI_CUSTOM_CLUSTER_FFF2_CMD_ID,
ESP_ZB_ZCL_ATTR_TYPE_OCTET_STRING,
buffer_size, &fff2_cmd_data_buffer,
true,
1, LUMI_MANUFACTURER_CODE);
buffer_size =
buildLumiFFF2CmdLinkParams2(fff2_cmd_data_buffer,
0x13,
timestamp,
_device.ieee_addr);
_gateway->sendAttributeWrite(
&_device,
LUMI_CUSTOM_CLUSTER,
LUMI_CUSTOM_CLUSTER_FFF2_CMD_ID,
ESP_ZB_ZCL_ATTR_TYPE_OCTET_STRING,
buffer_size, &fff2_cmd_data_buffer,
true,
1, LUMI_MANUFACTURER_CODE);
_gateway->sendAttributeRead(
&_device,
ESP_ZB_ZCL_CLUSTER_ID_THERMOSTAT,
ESP_ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID,
false);
Code: Select all
uint8_t fff2_cmd_data_buffer[0xAA];
time_t timestamp = time(nullptr);
if ((_trv_temperature_sensor_type == 0) ||
(_trv_temperature_sensor_type == 0xFF))
sendTRVExternalSensorInput(true);
uint8_t buffer_size =
buildLumiFFF2CmdSendTemperatureParams(fff2_cmd_data_buffer,
external_sensor_temperature);
_gateway->sendAttributeWrite(
&_device,
LUMI_CUSTOM_CLUSTER,
LUMI_CUSTOM_CLUSTER_FFF2_CMD_ID,
ESP_ZB_ZCL_ATTR_TYPE_OCTET_STRING,
buffer_size, &fff2_cmd_data_buffer,
true,
1, LUMI_MANUFACTURER_CODE);
_gateway->sendAttributeRead(
&_device,
ESP_ZB_ZCL_CLUSTER_ID_THERMOSTAT,
ESP_ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID,
false);
Bramka Zigbee <=> SUPLA
Więcej informacji tutaj:
https://forum.supla.org/viewforum.php?f=127
FAQ https://forum.supla.org/viewtopic.php?t=17277
Więcej informacji tutaj:
https://forum.supla.org/viewforum.php?f=127
FAQ https://forum.supla.org/viewtopic.php?t=17277
