Спасибо всем в треде за прекрасную работу - очень долго искал именно такую инфу и спустя полгода случайно наткнулся на этл.
Собрал схему из esp32 и cc1101, но кажется уперся в проблему - пакеты с ответом приходят на 1 из 100 запросов в среднем. Проверил, что на приём всё работает - пакеты с пульта и ответы счётчика получает стабильно. Видимо, дело в отправке пакетов.
Между cc1101 и счётчиком - ~100 метров и крыша дома, лист оцинковки и кусок пенопласта. Пытался покрутить конфигурацию, но ничего не получил. Завтра буду проверять прямо под столбом, с прямым line-of-sight, посмотрим насколько станет лучше.
Два вопроса: 1. Можно что-то ещё покрутить с модулем, чтобы увеличить мощность на отправку? Может стоит скрутить самодельную антенну побольше 2. Если не поможет, то есть у cc1101 рекомендованные аналоги?
Поставь E07-433m20S, тот же cc1101 только выходная мощность 100 мвт.
Спасибо за наводку, посмотрю. Только сейчас проверил спеки моего cc1101 - 10mW.
Провёл доп эксперименты: 1. Даже с почти прямой видимостью счётчика всё равно бывают сбои. 2. Без прямой видимости - доходит ~30 пакетов из ~500, и то нестабильно: то пробивается через ~5 попыток, то через ~105.
В целом, для моих целей сойдёт - если хотя бы несколько раз в сутки получится словить ответ счётчика, то для ведения статистики это допустимо.
Пока буду перекапывать код - хочется причесать его, чтобы было проще в нём ориентироваться. Буду постить апдейты по мере продвижения.
Наконец-то накостылял что-то рабочее под свой кейс. У этой версии 2 особенности: * Специально под мой юзкейс - оно постоянно спамит пакетом на получение sum/t1/t2, чтобы пробиваться через жуткие потери пакетов. * По пути растеряны все фичи из версий выше, кроме как "получить показания и отправить в mqtt" оно не умеет ничего.
Попробую потом добить mqtt discovery для home assistant, если разберусь с ним. А пока его нет, вот конфиг для hass:
Код:
- name: t1 unique_id: mirtek_XXXX_t1 device: identifiers: mirtek_XXXX_t1 name: mirtek_XXXX_t1 state_topic: mirtek/XXXX/T1 unit_of_measurement: kWh device_class: energy state_class: total value_template: "{{ value }}" - name: t2 unique_id: mirtek_XXXX_t2 device: identifiers: mirtek_XXXX_t2 name: mirtek_XXXX_t2 state_topic: mirtek/XXXX/T2 unit_of_measurement: kWh device_class: energy state_class: total value_template: "{{ value }}"
Создаёт 2 устройства, в каждом из них одно показание. Юниты и классы прописаны так, чтобы оно подключалось к Energy.
Доброго времени суток! Первый раз читаю по ардуински (и второй на С), поэтому не совсем всё понимаю... 1. Без подключения к MQTT счетчик не опрашивается, что ли? Ибо если заработает, планирую прикрутить дисплей. 2. Правильно ли я понял, MQTT.h не цепляет никаких подходящих для отправки GETом зависимостей? (с этим вроде разобрался, нашёл WiFi.h) 3. Используя ELECHOUSE_cc1101.setGDO(GDO0, GDO2) вместо ELECHOUSE_cc1101.setGDO0(GDO0) я же смогу переместить оба?
1. Без подключения к MQTT счетчик не опрашивается, что ли? Ибо если заработает, планирую прикрутить дисплей.
Изначально цикл получения показаний по таймеру построен таким образом, что проверяется подключены ли мы к MQTT серверу или нет. Уберите следующее примерно:
Код:
mqttClient.loop();
if (needMqttConnect) { if (connectMqtt()) { needMqttConnect = false; } } else if ((iotWebConf.getState() == iotwebconf::OnLine) && (!mqttClient.connected())) { Serial.println("MQTT reconnect"); connectMqtt(); }
а так же:
Код:
//Запрос показаний по таймеру if ((iotWebConf.getState() == iotwebconf::OnLine) && (mqttClient.connected())) {
в этой строке уберите просто проверку:
Код:
&& (mqttClient.connected()))
а так же просто закомментируейте всё, что связано с вызовами MQTT, например можно убрать, если Вам не нужно, все функции связанные с MQTT, например packetSender_1_mqtt(), packetSender_2_mqtt(), packetSender_3_mqtt(), packetSender_4_mqtt(), и их вызовы.
Решил немного переделать автоматику в доме, и понадобилось интегрировать устаревший но работающий мост Миртек32 ->MQTT в другое устройство. Посмотрел код, даже актуальный сейчас.. и понял, что это будет больно для отладки и скрещивания с другим кодом Особенно с учётом времени компиляции проектов ESP32 с WEB функциями)
Короче запилил что-то вроде библиотеки, чтобы можно было легко и просто добавить в любой свой проект функцию общения со счётчиком. У себя добавлю в автоматику отопления, на базе доски с кучей реле и esp32 с али. Ну и заодно немного подправил парсеры на свой вкус. Ну и всякие рюшечки вроде красивого вывода байт. Работает вроде неплохо, без левых значений.
Пояснения по коду: -Из кода удалено всё что связано с WEB, WIFI и MQTT. Только простой пример Serial. Но с ним очень легко разобраться для внедрения в свои проекты. Сторонние библиотеки устанавливать больше не нужно, в комплекте проверенно-работоспособные библиотеки. Всё что нужно сделать, это буквально прописать эти строки:
постоянно спамит пакетом на получение sum/t1/t2, чтобы пробиваться через жуткие потери пакетов
Помимо CC1101 (10мВт) можно использовать E07-M1101D (100мВт), если наблюдаются проблемы со связью
PS: когда будете использовать в реальном исполнении, прикрутите пару GyverTimer и делайте запросы MIRT_update(1-4) с разным интервалом, не спамьте счётчик и эфир запросами MIRT_update(0). К тому же в MIRT_update(0) используются delay, что может негативно сказаться на устойчивости MQTT. PSPS: В дополнение - безумно кривой, но работоспособный сниффер, для анализа обмена с пультом. Делалось на скорую руку, править уже нужды нет. В виде "Как есть".
Вот немного доработали код: 1. Добавлена поддержка 1-фазного счетчика (команды 0x1C; 0x05, 0x00; 0x2B, 0x00; 0x10); 2. Решили что табличка для 1-фазного счетчика не нужна, так как всего 1 фаза; 3. Исправлен парсинг реактивной энергии (оказывается старший бит отвечает за знак, в инструкции данная ситуация для этого параметра не описана); 4. Добавлено автоматическое обновление страницы (<meta http-equiv="refresh" content="60"> - обновление раз в минуту); 5. Добавлен разворот таблицы для 3-фазного счетчика (bool horizontal = true) по-умолчанию таблица горизонтальна; 6. Добавлена суммирующая строка для таблицы 3-фазного счетчика (Суммировать напряжение и косинус фи нет смысла. Суммирование реактивной энергии происходит по модулю, согласно суммарным показаниям получаемых со счетчика); 7. Добавлен парсинг состояния пломб и состояние реле нагрузки; 8. Найдена ошибка в некоторых версиях софта 1-фазных счетчиков (на стороне счетчика) для команды 0x2B, 0x00: ошибка заключается в том, что в ответный пакет от счетчика добавили 1-байт = 0x76, идущий перед CRC, тем самым увеличив длину пакета с 43 до 44 байт, но при этом CRC считается только для 43-байт (скорей всего параметры счетчика цикла для расчёта CRC заданы программистами вручную и их забыли поправить). За что отвечает добавленный байт не ясно.
Пример полученного пакета с неверно посчитанным CRC для 1-фазного счётчика (точнее CRC будет не верным у нас, так как мы считаем CRC от всего пакета): Спойлер
Я не пойму, то, что выделил, до обработки или уже после ? и CRC у вас считается когда, до или после ? 73 55 1E 0 FE FF ХХ ХХ 5 98 43 C7 0 0 62 1 0 1 0 55 93 0 0 55 93 0 0 14 72 0 0 41 21 0 0 0 0 0 0 0 0 0 0 1A 55
0x55 после байт стаффинга CRC считается от всего пакета (43/44 байта, так как берётся длина минус последние 2 байта, где CRC и стоп-байт) Если отбросить проверку CRC и сместить стоп-байт для пакета из 44 байт, то всё парсится верно, так же как и для 43-байтового пакета, но уже с проверкой CRC, что реализовано в условиях проверок в парсинге 3_1
Я не пойму, то, что выделил, до обработки или уже после ? и CRC у вас считается когда, до или после ? 73 55 1E 0 FE FF ХХ ХХ 5 98 43 C7 0 0 62 1 0 1 0 55 93 0 0 55 93 0 0 14 72 0 0 41 21 0 0 0 0 0 0 0 0 0 0 1A 55
CRC считается после обработки байтстаффингом (так как согласно инструкции CRC тоже подвергается прямому и обратному байтстафыингу). А что тут не так? Всё парсится, CRC совпадает. Просто не сразу заметил что это ответ на команду 0x05 0x00. Спойлер
Код:
void packetReceiver() //функция приёма пакета (помещает его в resultbuffer[]) { for (int i = 0; i < 50; i++) { resultbuffer[i] = 0x00; tempbuffer[i] = 0x00; }
tmr.start(); packet = ""; //переменная для вывода полученного пакета в MQTT int PackCount = 0; //счётчик принятых из эфира пакетов bytecount = 0; //указатель байтов в результирующем буфере bytecounttemp = 0; //указатель байтов в промежуточном буфере while (!tmr.tick() && PackCount != packetType) { if (ELECHOUSE_cc1101.CheckReceiveFlag()) { PackCount++; /* //Rssi Level in dBm Serial.print("Rssi: "); Serial.println(ELECHOUSE_cc1101.getRssi());
//Get received Data and calculate length int len = ELECHOUSE_cc1101.ReceiveData(buffer);
//подшиваем 1/3 или 1/4 пакета в общий пакет for (int i = 1; i < len; i++) { tempbuffer[bytecounttemp] = buffer[i]; bytecounttemp++; //Считаем длину промежуточного буфера } ELECHOUSE_cc1101.SpiStrobe(0x36); // Exit RX / TX, turn off frequency synthesizer and exit ELECHOUSE_cc1101.SpiStrobe(0x3A); // Flush the RX FIFO buffer ELECHOUSE_cc1101.SpiStrobe(0x3B); // Flush the TX FIFO buffer //delay(1); ELECHOUSE_cc1101.SpiStrobe(0x34); // Enable RX } } /////////////////////////////////////////////////////////////////////////////////////////////// // Обработка байтстаффингом полученного пакета перед парсингом /////////////////////////////////////////////////////////////////////////////////////////////// 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++; //Компенсируем индекс результирующего буфера при пропуске байта } } /* //Add by DigiBoy if (tempbuffer[i] == 0x55 and tempbuffer[i - 1] != 0x73) { break; }*/ }
Serial.print("Packets received: "); Serial.println(PackCount); //Печатаем общий пакет for (int i = 0; i < bytecount; i++) { Serial.print(resultbuffer[i], HEX); //исходный пакет Serial.print(" "); packet += String(resultbuffer[i], HEX); //собираем пакет для вывода в MQTT packet += " "; } Serial.println(); Serial.print("Packet lengt: "); Serial.println(bytecount); // Считаем свою CRC ---------- 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); //----------
//Вывод полученного пакета в MQTT packet.toUpperCase(); //Приводим все значения к верхнему регистру mqttClient.publish("mirtek/" + (String)MeterAdressValue + "/Packet_recive", packet); }
2 reseived from serial Packet sent: 10 73 55 21 0 XX XX FE FF 5 0 0 0 0 0 AD 55 Packets received: 4 73 55 1E 0 FE FF XX XX 5 98 43 C7 0 0 62 1 0 1 0 55 93 0 0 55 93 0 0 14 72 0 0 41 21 0 0 0 0 0 0 0 0 0 0 1A 55 Packet lengt: 45 1E 0 FE FF XX XX 5 98 43 C7 0 0 62 1 0 1 0 55 93 0 0 55 93 0 0 14 72 0 0 41 21 0 0 0 0 0 0 0 0 0 0 Calculate myCRC: 1A SUM: 377.17 - 19-22 байт 0x55 0x93 0x00 0x00 (Сумма полная, так же дублируется в 23-26 байтах как сумма по задействованным тарифам) T1: 292.04 - 27-30 байт 0x14 0x72 0x00 0x00 T2: 85.13 - 31-34 байт 0x41 0x21 0x00 0x00 T3: 0.00 - 35-38 байт 0x00 0x00 0x00 0x00 T4: 0.00 - 39-42 байт 0x00 0x00 0x00 0x00
Можно увидеть "неправильный" сырой пакет, до преобразования?
Если только до выходных не изменятся показания того однофазного счетчика, так как надо в код добавить вывод пакета до байтстаффинга, а 0x55 0x93 0x00 0x00 как раз попадают в формирование суммарных показаний.
Интересно другое, как с "кривыми" данными работает выносной пульт ? 73 55 1C 0 FE FF XX XX 2B 98 43 C7 0 0 1 0 1 0 0 0 8 80 89 13 56 0 47 58 0 0 0 0 20 0 0 23 0 0 3 0 0 76 82 55
Нормально получает данные, так как счётчик в байте CRC передаёт значения для пакета из 43 байт, а так как в счётчике и пульте, судя по всему, в цикле используются ручные границы (длина пакета) и всё совпадает, то всё парсится. Или сделали как в моём коде, сдвигаем стоп-байт на +1 и выкидываем проверку CRC для 44-байтового пакета или просто считаем CRC от 43 из 44, главное испортить с двух сторон. И вообще пока не понятно зачем и что значит добавленный байт равный 0x76?!
Вот разбор данного пакета:Спойлер
Последний раз редактировалось SysCat Ср май 29, 2024 11:31:11, всего редактировалось 1 раз.
Сейчас этот форум просматривают: vortep1955 и гости: 9
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения