Термостат для теплого пола K5H
В качестве основы был взят термостат с Али-Экспресс неизвестного производителя K5H16A-wifi.
Конструктивно, термостат построен на собственном контроллере, который выполняет все функуии термостата, а для удаленного управления используется стантартный Wi-Fi модуть Tuya. Соответственно, модуль Tuya убирается, а на его место, через специальный переходник, ставится nRF52.
Протокол TUYA
Исследование показало следующие параметры, которые контролирует протокол Tuya:
ID | Type | Example value | Description |
0x01 | BOOL | 1 | выключатель питания |
0x02 | ENUM | 0 | ручной (0) -автоматический (1) режимы |
0x10 | VALUE | 9 | установленная температура |
0x18 | VALUE | 207 | температура датчика |
0x0a | BOOL | 0 | low Temperature Protection |
0x13 | VALUE | 94 | maximum tempersature |
0x1a | VALUE | 100 | minimum temperature |
0x1b | VALUE | 254 | temperature adjustement (signed) |
0x1f | ENUM | 1 | weekly programming |
0x27 | BOOL | 0 | restore factory default |
0x28 | BOOL | 0 | child lock |
0x2b | ENUM | 0 | NTC (temperature sensor) select (0 - in, 1 - out, 2 - all) |
0x1e | DATA | 06 00 00 dc 08 00 00 dc 0b 1e 00 dc 0c 1e 00 dc 11 00 00 dc 16 00 00 dc 08 00 00 dc 17 00 00 dc | расписание: uint8_t - часы, uint8_t - минуты, int16_t - температура |
0x2c | VALUE | 20 | яркость подсветки (0 - 99) |
0x24 | ENUM | 0 | статус нагревателя: (0) - нагрев, (1) - ожидание |
0x2d | BITMAP | 00 | ??? |
Проблемы
- В термостатах есть заводской брак: перепутаны местами резисторы R22 и R23 на главной плате. Эти резисторы отвечают за измерение температуры с внешнего датчика. Из-за этого, если переключиться на внешний датчик, температура всегда будет -9.5 градусов. Необходимо перепаять эти резисторы и все станет как надо. Должно быть так: R22 - 1K, R23 - 10К.
- Непонятно, как устанавливать часы с панели управления. Часы не идут, если модел не отвечает на сообщение SET_SYSTEM_TIME. Однако, ответ на это сообщение изменяет время на термостате. Следует:
- либо установить, как термостат передает время модулю;
- либо узнать, как заставить идти часы без изменения времени на термостате.
- В оригинале, часы не идут без подключения к сети. Видимо, без RTC модуля, термостат может брать время только из модуля Tuya, и смысла в ручной установке нет.
- В спецификации BT Mesh нет модели для термостата. И, если в сенсор я еще могу запихнуть желаемую и текущую температуры, то уже выставить первую уже нельзя. Разве что, с помощью Generic Property. Но у термостатов, обычно, есть еще несколько состояний, вроде режима работы, расписаний и т.п. Придется городить что-то свое, но для кастомных сообщений нужно иметь свой Vendor ID, которого у меня нет и не предвидется. Придется взять временно чей-то чужой. Я рассматриваю Id'шник от 3Com, так как компании уже нет и производить BT MESH от из имени вряд ли кто будет.
Список реализованных моделей
Received composition:
Feature support:
relay: yes
proxy: yes
friend: yes
lpn: no
Element 0:
location: 0000
SIG defined models:
Model ID 0000 "Configuration Server"
Model ID 0002 "Health Server"
Model ID 1000 "Generic OnOff Server"
Model ID 1002 "Generic Level Server"
Model ID 1004 "Generic Default Transition Time Server"
Model ID 1203 "Scene Server"
Model ID 1204 "Scene Setup Server"
Model ID 1100 "Sensor Server"
Model ID 1101 "Sensor Setup Server"
Model ID 1202 "Time Client"
Vendor defined models:
Model ID 0005 0000
Model ID: 0005 0000 - это и есть кастомная модель термостата.
ВНИМАНИЕ! Id для Vendor Specific модели предполагают наличие кода производителя (Vendor Id) и у меня такого Id нет. Исключительно для отладки я взял идентификатор не существующей ныне фирмы 3Com, так как вероятность, что появятся на рынке BT Mesh устройства от них - крайне мала. Я понимаю, что делать так нехорошо. В реальных устройствах данный идентификатор использовать не следует.
Кастомная BT модель для термостата.
/* Thermostat model message opcodes. */
typedef enum {
THERMOSTAT_OPCODE_GET = 0x00,
THERMOSTAT_OPCODE_SET,
THERMOSTAT_OPCODE_STATUS,
THERMOSTAT_OPCODE_RANGE_GET,
THERMOSTAT_OPCODE_RANGE_STATUS,
} thermostat_opcode_t;
/* status values for thermostat_status_msg_pkt_t */
typedef enum {
THERMOSTAT_STATUS_GOOD = 0,
THERMOSTAT_STATUS_INVALID_MODE,
THERMOSTAT_STATUS_INVALID_TEMPERATURE
} thermostat_status_t;
/* mode values for thermostat_status_msg_pkt_t */
typedef enum {
THERMOSTAT_MODE_MANUAL = 0,
THERMOSTAT_MODE_AUTO
} thermostat_mode_t;
/** Message format for Thermostat Set. */
typedef struct __attribute((packed)) {
uint8_t mode : 2;
uint8_t padding : 6;
uint16_t temperature;
} thermostat_set_msg_pkt_t;
/** Message format for Thermostat Status. */
typedef struct __attribute((packed)) {
uint8_t status_code;
uint8_t onoff_status : 1;
uint8_t mode : 2;
uint8_t heater_status : 1;
uint8_t padding : 4;
uint16_t target_temperature;
uint16_t present_temperature;
} thermostat_status_msg_pkt_t;
/** Message format for Thermostat Range Status. */
typedef struct __attribute((packed)) {
uint16_t min_temperature;
uint16_t max_temperature;
} thermostat_range_status_msg_pkt_t;
Ошибки
- Значения температур определены как беззнаковые, в то время, как температура может быть отрицательной.
Ссылки