Не спорю, за что огромное спасибо! Но не было температуры и некоторых других показателей. Зато позволяет представлять визуально что происходит при парсинге. Что за что отвечает и при каких входных данных. Согласно Вашим выкладкам и предыдущим скетчам и была сделана табличка:
Так же нашлась примерная схема оптопорта, не считая преобразователя UART-USB Спойлер Если у Миртек такие же команды как в описании протокола Star 104 304 1.20, то команда 0x2A (Чтение записи из журнала) так же не интересна для нас.
Тогда: команда 0x10 - ReadConfigure (Чтение конфигурации) не очень интересно
Код:
Чтение конфигурации Входные данные (0 байт): Выходные данные (19 байт): 1 байт - конфигурационный байт; 1 байт - Бит 0 – автоматический переход на зимнее/летнее время (1 - включено); Бит 2,1 – действующее тарифное расписание (0- раб,1-суб,2-вос,3-спец); Бит 3 - резерв; Бит 4 - резерв; Бит 5 - резерв; Бит 6 - Включение парольной защиты чтения информации абонента; Бит 7 - резерв; 1 байт – время индикации (в секундах, 5 <= t <= 60); 1 байт - Количество попыток доступа с неправильным паролем до блокировки интерфейса, 0-отключено; 1 байт - Ресурс батарейки (полное количество месяцев работы); 1 байт - Ресурс батарейки (количество оставшихся месяцев работы); 1 байт - День сохранения месячного среза по электроэнергии; 1 байт - День сохранения месячного среза по воде; 1 байт - День сохранения месячного среза по газу; 1 байт - Интервал усреднения профилей мощности; 1 байт - Роль устройства (информационный идентификатор, см. Таблицу 2); 1 байт - Побитовая информация о наличии реле: 1-реализовано в железе, 0-отключено. (0й-4й биты - реле №0-№4) 1 байт - Побитовая информация о типе управления реле: 1-импульсом 0,5 сек., 0-уровнем. (0й-4й биты - реле №0-№4) 1 байт - Побитовая информация о статусе реле: 1-разомкнуто, 0-замкнуто. (0й-4й биты - реле №0-№4) 1 байт - Побитовая информация о наличии пломб:1-реализовано в железе, 0-отключено. (0й-4й биты - реле №0-№4) 1 байт - Побитовая информация о статусе пломб:1-реализовано в железе, 0-отключено. (0й-4й биты - реле №0-№4) 1 байт - Код модуля связи на UART1. См. таблицу кодов; 1 байт - Код модуля связи на UART1. См. таблицу кодов; 1 байт - Код модуля связи на UART1. См. таблицу кодов.
только если это брать:
Код:
1 байт - Побитовая информация о статусе реле: 1-разомкнуто, 0-замкнуто. (0й-4й биты - реле №0-№4) 1 байт - Побитовая информация о наличии пломб:1-реализовано в железе, 0-отключено. (0й-4й биты - реле №0-№4) 1 байт - Побитовая информация о статусе пломб:1-реализовано в железе, 0-отключено. (0й-4й биты - реле №0-№4)
команда 0x05 (0x04 подкоманда) не описана, возможно ошибки как и с командой 0x28 дополнительных режимов индикации, и она не имеет 14-го байта, а значит скорей всего должна формироваться с длиной 0x20 без 14-го байта и получать 3 пакета, а не 4. (надо проверять)
команда 0x0A (0x01 подкоманда) не описана данная команда вообще (возможно ошибочная).
В Ваших изысканиях указана дата 03/04/2022, что предполагает что это Вс, согласно описанию
Код:
0x1C - ReadDateTime Чтение времени и даты Входные данные (0 байт): Выходные данные (7 байт): 7 байт: секунды, минуты, часы, день недели (Пн-1,Вт-2,Ср-3,Чт-4,Пт-5,Сб-6,Вс-0), день, месяц, год.
получается, что между временем и датой - день недели, у Вас 0x00, что соответствует Вс в описании вторая строка (получение ответа) между 0x13 0x26 0x05 и 0x03 0x04 0x16 стоит 0x00 - вс (надо проверить)
Если все так, то согласно этому протоколу для нас интересны следующие команды: 0x24 - Чтение значений энергии по тарифам и суммарно, сохраненных на начало текущего и 35 предыдущих месяцев 0x25 - Чтение значений энергии по тарифам и суммарно, сохраненных на конец суток, за прошедшие 128 суток 0x29 - Чтение значений сетевого напряжения (не особо имеет смысл отдельно при запросе мгонвенных значений 0x2B 0x00)
Код:
Входные данные (1 байт): 1 байт: номер фазы, для однофазный устройств - число 1; для трехфазных устройств (числа – 1,2,3). Выходные данные (3 байт): 1 байт - номер фазы, для однофазный устройств - число 1; для трехфазных устройств (числа – 1,2,3); 2 байта - значение напряжение сети (для приведения к кВт значение необходимо делить на 100);
Address Source: Адрес программы опроса = 0xFFFF - в Ваших выкладках как раз он установлен в 0xFF 0xFF, а в скетче 0x09 0xFF, интересно что отправляет сам пульт, что бы маскироваться под него. Да и в принципе и всё.
Последний раз редактировалось SysCat Ср июн 28, 2023 21:21:11, всего редактировалось 1 раз.
...Address Source: Адрес программы опроса = 0xFFFF - в Ваших выкладках как раз он установлен в 0xFF 0xFF, а в скетче 0x09 0xFF, интересно что отправляет сам пульт, что бы маскироваться под него. Да и в принципе и всё.
вторая строка (получение ответа) между 0x13 0x26 0x05 и 0x03 0x04 0x16 стоит 0x00 - вс
между временем и датой есть байт который показывает день недели по календарю
Код:
0x1C - ReadDateTime Чтение времени и даты Входные данные (0 байт): Выходные данные (7 байт): 7 байт: секунды, минуты, часы, день недели (Пн-1,Вт-2,Ср-3,Чт-4,Пт-5,Сб-6,Вс-0), день, месяц, год.
Добавил в скетч вывод дня недели. (XX XX - номер счетчика в HEX)
Код:
Packet sent: F 73 55 20 0 XX XX FE FF 1C 0 0 0 0 5C 55 Packets received: 3 73 55 7 0 FE FF XX XX 1C A8 43 5B 0 D 33 15 3 1C 6 17 E8 55 Packet lengt: 22 7 0 FE FF XX XX 1C A8 43 5B 0 D 33 15 3 1C 6 17 E8 Last Request: 28-06-23 21:51:13 Ср
Цитата:
команда 0x05 (0x04 подкоманда) не описана, возможно ошибки как и с командой 0x28 дополнительных режимов индикации, и она не имеет 14-го байта, а значит скорей всего должна формироваться с длиной 0x20 без 14-го байта и получать 3 пакета, а не 4. (надо проверять)
Проверил, был не прав, все же используется длинный запрос с 14-м байтом, который равен следующему:
Теперь понял к чему была картинка загруженная по какой-то ссылке "CQ_DAT.jpg" вроде как от Dismas
Тогда запрос 0x05, 0x00 - запрос суммарных показаний для активной прямой энергии, а запрос 0x05, 0x04 - запрос суммарных показаний для абсолютной активной энергии, но разницы в показаниях 0x00 и 0x04 не увидел, абсолютная=прямая+обратная, странно, что не абсолютная=прямая-обратная, но мы же не продаем обратно энергию энергоснабжающей компании, поэтому реверсивная у нас должна быть равной 0, но на картинке Реактивная Прямая =0,26; Реактивная Обратная = 0,16, а Реактивная абсолютная сумма R+ + R-, хотя разумнее было бы R+ - R-, а остаток у нас к оплате, но так получается это сумма прокачанной энергии и не важно её направление, если я правильно понял . А значит, что нам полезны только команды 0x05, 0x00 и 0x05, 0x02, но нужны ли нам значения 0x05, 0x02, думаю что нет.
Цитата:
Мой пульт отправляет 0xFEFF
Поменял в скетче, поставил вместо 0x09 0xFF Ваши значения 0xFE 0xFF
Код:
transmitt_byte[7] = 0xfe; // было 0x09 transmitt_byte[8] = 0xff;
Вложения:
Комментарий к файлу: Обновления 7: добавлен день недели, замена 0x09 0xFF на 0xFE 0xFF, отрицательные косинусы, немного чистки, комментарии кода и немного логического размещение кода My_Mirtek_GW_upd7.zip [8.13 KiB]
Скачиваний: 122
Всем привет. Обновил прошивку своей esp32 на последнюю SysCat. Но ничего не работает. Подключаюсь к точке доступа, настройки вводу. К wifi подключается только если плата esp32 лежит рядом с роутером. Чуть дальше и все, нет подключения. После подключения к wifi я вижу ip платы, но не могу войти в нее. На mqtt ничего не приходит. Через serial порт если смотреть данные, то такое ощущение, что плата зависает.
Всем привет! А никто не смотрел в сторону EspEasy? Там и OTA, и вэбморда. И плагин CC1101 есть, который можно, наверное, взять за основу. Сам, к сожалению, не программист, поэтому могу поучаствовать только как тестировщик, морально и материально даже )
Всем привет. Обновил прошивку своей esp32 на последнюю SysCat. Но ничего не работает. Подключаюсь к точке доступа, настройки вводу. К wifi подключается только если плата esp32 лежит рядом с роутером. Чуть дальше и все, нет подключения. После подключения к wifi я вижу ip платы, но не могу войти в нее. На mqtt ничего не приходит. Через serial порт если смотреть данные, то такое ощущение, что плата зависает.
В прошивке нет влияния на уровень мощности Wi-fi.
А Вы физически переключили gdo0 с GPIO2 (вывод D2) на GPIO22 (вывод D22)?
GPIO2 - подключен на встроенный светодиод. Быстрые мигания 30 сек. - поднята точка доступа, Медленные мигания - попытка подключения в Вашему Wi-fi в роли клиента, Горение светодиода - подключен к MQTT серверу.
В коде был изменен номер вывода, соответственно физически тоже нужно поменять, или вернуть в коде обратно. Было:
Код:
int gdo0 = 2;
Стало:
Код:
int gdo0 = 22;
Попробуйте переключить или поменять в коде. Веб страница становится доступна только после переключения платы с режима точки доступа на режим клиента Wi-fi. Но в Serial должны выводится состояния платы:
Код:
st:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:1 load:0x3fff0018,len:4 load:0x3fff001c,len:1216 ho 0 tail 12 room 4 load:0x40078000,len:10944 load:0x40080400,len:6388 entry 0x400806b4 Config version: mirtek_gw_v1 Config size: 555 Loading configurations [iwcAll] |-- [iwcSys] | |-- 'iwcThingName' with value: 'Mirtek_GW' | |-- 'iwcApPassword' with value: <hidden> - пароль на веб страницу | |-- [iwcWifi0] | | |-- 'iwcWifiSsid' with value: 'ВАША ТОЧКА ДОСТУПА' | | \-- 'iwcWifiPassword' with value: <hidden> - пароль к Вашей точке доступа | \-- 'iwcApTimeout' with value: '30' - таймер 30 сек. |-- [iwcCustom] | |-- [mqtt] | | |-- 'mqttServer' with value: 'IP адрес MQTT сервера' | | |-- 'mqttUser' with value: 'Логин на MQTT сервере' | | \-- 'mqttPass' with value: <hidden> - пароль к учетке MQTT сервера | \-- [group1] | \-- 'MeterAdress' with value: 'Номер счетчика' \-- [hidden] Ready. SPI Connection CC1101 OK - соединение с CP1101 State changing from: 0 to 2 - не знаю почему в библиотеке так, но разумнее было 0 to 1 Setting up AP: Mirtek_GW - поднята точка доступа. Роль - сервер Use password: <hidden> - по умолчанию пароль 12345678 AP IP address: 192.168.4.1 - IP адрес в режиме точки доступа для настроек AP timeout (ms): 30000 - таймер локальной точки доступа для настроек - 30 сек. State changed from: 0 to 2 - не знаю почему в библиотеке так, но разумнее было 1 to 2 State changing from: 2 to 3 Connecting to [ВАША ТОЧКА ДОСТУПА] (password is hidden) - подключение к Вашей точке доступа в роли клента WiFi timeout (ms): 30000 - таймер для подключения к Вашей точке доступа - 30 сек. State changed from: 2 to 3 WiFi connected - подключено к Вашей точке доступа IP address: ЛОКАЛЬНЫЙ IP-адрес от полученный роутера State changing from: 3 to 4 Active mDNS services: 1 Accepting connection State changed from: 3 to 4 Connecting to MQTT server... - подключение к MQTT серверу Connected! - подключен к MQTT серверу
При обновлении прошивки все настройки хранимые в памяти не переписываются, проверьте корректность настроек.
В самой структуре MQTT топика также были сделаны изменения, добавлен еще один подуровень в виде номера счетчика. Было:
Код:
"mirtek/параметры и зачения"
Стало:
Код:
"mirtek/" + (String)MeterAdressValue + "/параметры и значения"
Где (String)MeterAdressValue - номер счетчика из настроек, соответственно путь стал mirtek/12345/параметры и значения
А никто не смотрел в сторону EspEasy? Там и OTA, и вэбморда. И плагин CC1101 есть, который можно, наверное, взять за основу
Там скорей всего эта настройка рассматривается просто как "труба" UART (Serial) между ESP и CC1101, так же есть модули которые в себе. содержат дополнительный контроллер и на входе там уже UART, а не SPI как в нашем случае.
Один из примеров - принятый пакет: 73h,55h,7,0,0FFh,0FFh,7Ch,64h,1Ch,0A8h,5,5Bh,0,13h,26h,5,0,3,4,16h,73h,22h,55h Видим стандартная длинна +7 байт, а в пакете на 1 байт больше. CRC не сойдётся, нужно произвести обратный байтстаффинг, и только после этого подсчитывать CRC и сравнивать с тем, что имеется в пакете на предмет "правильности"
Согласно структуре пакета вроде предпоследний байт?? - 22h должна быть. Функции приёма и передачи пакетов я не трогал, только 1 параметр в функции формирования пакета для передачи. Я не писать, я читатель , я только один байт в параметре передачи пакета поправил, проверки CRC вроде там нет в коде, а все нужные параметры приходят и при 0x9F 0xFF, и при 0xFF 0xFF, и при 0FE 0xFF, ранее в коде то вообще в одном пакете передавали 0x9F 0xFF, а другом месте 0xFF 0xFF передавали.
При отправке стали CRC так:
Код:
//вычисляем и добавляем байт crc crc.restart(); crc.setPolynome(0xA9); for (int i = 3; i < (transmitt_byte[0] - 1); i++) { crc.add(transmitt_byte[i]); }
а при приеме пакета так:
Код:
crc.reset(); crc.setPolynome(0xA9); for (int i = 2; i < (bytecount - 2); i++) { crc.add(resultbuffer[i]); Serial.print(resultbuffer[i], HEX) Serial.print(" "); } Serial.println(); myCRC = crc.getCRC(); Serial.print("Calculate myCRC: "); Serial.println(myCRC, HEX);
Вынужден разочаровать, в данном случае, CRC 73 потому как имеет место байтстаффинг. Смотрим описание протокола обмена: При формировании пакета, если между стартовыми байтами 73 55 и стоповыми 55 имеются 73 или 55, то они заменяются на последовательности 73 22 и 73 11 соответственно. В данном конкретном случае 73 22 что эквивалентно 73. При разборе пакета необходимо проверять наличие старт-стоп последовательности а между ними наличие байтстаффинга. (Длинна пакета в любом случае остаётся правильной, о чём я говорил раньше.) После этого подсчитывать CRC сравнивать с имеющейся в пакете и только после этого парсить пакет. Если этого не делать, появляются мистические "кривые" ответы.
Это если действительно заниматься сравнением CRC и отсечением неверных пакетов, но слишком завышенные значения уже отсекаются после парсинга и на сервер в MQTT не идут, но в WEB интерфейсе будут отображаться. Конечно это не правильно, но как говорится испорчено было до меня, а разбираться в чужом коде то еще веселье, но я почти разобрался и можно будет прикрутить проверку CRC и отправка повторных запросов счетчику в случае получения некорректных битых пакетов. Вы конечно правы, просто пока руки до CRC не дошли еще, попробую разобраться с этим волшебным байстаффингом. Но всему свое время. Пока хоть и с костылями и так работает, а так бы переписать все нафиг.
...попробую разобраться с этим волшебным байстаффингом...
Он нужен по одной причине: отделить стартовую/стоповую последовательность от информационных байтов между ними, не более того. Название правда громкое, впрочем это так же как анчоус, красиво, громко а на деле - обычная хамса
Так разделение в коде происходит, ответный пакет кладется просто в массив байтов, откуда парсится тупо по элементам. Старт/стоп проверяется в условиях парсинга что они на своих местах:
Код:
if ((resultbuffer[0] == 0x73) and (resultbuffer[1] == 0x55) and (resultbuffer[2] == 0x07) and (resultbuffer[6] == (atoi(MeterAdressValue) & 0xff)) and (resultbuffer[7] == ((atoi(MeterAdressValue) >> 8) & 0xff)) and (resultbuffer[21] == 0x55))
Элементы 0, 1 - старт, 21 - стоп, остальное данные
Но Вы правы, надо сделать все по уму, чтобы перезапрашивать так же битые пакеты. Будем разбираться, пока в отпуске и далеко от пульта. Не обижайтесь!
И в описании протокола написано только:
Цитата:
Байтстаффингу подвергаются все байты пакета за исключением стартовых и стопового. Стартовая последовательность - 0х73 0х55, стоповая - 0х55, все что между ними, подлежит байтстаффингу. При байтстаффинге анализируется каждый байт, и: 0х55 заменяется на 0х73 0х11, 0х73 заменяется на 0х73 0х22. При обратном байтстаффинге проводится противоположная замена.
И немного не понимаю как он работает? Только замена определенной последовательности на определённую другую? Тут только определенные байты приводятся. Простите за глупость, но я пока не понимаю как работает этот байтстаффинг для остальных данных. С CRC всё куда понятнее и пример расчёта приведён хоть и для Delphi.
...но я пока не понимаю как работает этот байтстаффинг для остальных данных...
Странно, вроде бы однозначно написано в стандарте... ну ладно, попробую ещё раз. И так: -Стартовая последовательность имеет вид 73 55 далее идут всякие разные данные, маркером конца служит байт 55. По этим признакам находят начало/конец пакета. Теперь предположим, что в середине пакета имеется один или несколько байтов данных со значением 55. Как их рассматривать ? Как маркер конца пакета ? Или имеется байты со значением 73 , как его воспринимать ? Для того, что бы разделить данные и маркеры начала и конца, и введено это самое понятие байтстаффинг , где заменяются некоторые байты на последовательности 73 11 и 73 22. Как обрабатывать ? Находим стартовую последовательность 73 55, далее последовательно сравниваем все байты с 73, если таковой находим, проверяем следующий за ним байт, если это 11 то заменяем эти два байта на 55, если это 22 то заменяем эти два байта на 73 и так до маркера конца пакета 55. Только после этого длинна пакета будет верной, а его CRC при расчёте будет правильной. Другие байты не изменяются.
Спасибо за помощь, Dismas! Просто я думал что для других входных данных другие выходные, а оказывается все просто, только 73 и 55 в данных обрабатываем ну и соотвественно 73 11 и 73 22. Вернусь с отпуска тогда буду реализовывать это, а так же можно спокойно будет добавить проверку CRC и перезапрос битых пакетов. Вместе - сила!
Добавил обработку принятого пакета обратным байтстаффингом. Для отправляемого пакета пока вроде особо не нужен байтстаффинг, так как пока в очень крайнем случае только байты с номером счетчика могут стать 0x73 или 0x55, остальные в текущий момент отличны от них и не требуют замены.
На идеальность и оптимизированность кода не претендую:
Код:
int j = 0; //Значение компенсирующего смещения индекса for (int i = 0; i < bytecounttemp; i++) { resultbuffer [i-j] = tempbuffer[i]; //Записываем текущее значение байта из временного буфера в выходной bytecount++; //Считаем длину результирующего буфера if (tempbuffer[i] == 0x73 and (i + 1 < bytecounttemp)) { if (tempbuffer[i + 1] == 0x11) //Проверяем что последовательность 0x73 0x11 { resultbuffer[i-j] = 0x55; //Меняем последовательность 0x73 0x11 на 0x55 i++; //Пропускаем следующий байт j++; //Компенсируем индекс результирующего буфера при пропуске байта } if (tempbuffer[i + 1] == 0x22) //Проверяем что последовательность 0x73 0x22 { i++; //В результирующем буфере уже лежит 0x73 вместо 0x73 0x22, пропускаем следующий байт j++; //Компенсируем индекс результирующего буфера при пропуске байта } } }
Так же временно добавил вывод отправленного/принятого пакета в MQTT для контроля. Отключены проверки на предельные значения (ранее был такой костыль). Пока запредельных значений не прилетало, еще тестирую. Добавлена проверка CRC.
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения