sgrimee / smarty-reader

Read smart electricity and gaz counter with Arduino
GNU General Public License v3.0
8 stars 4 forks source link

Workaround for random no received data #6

Closed piltous closed 2 years ago

piltous commented 3 years ago

Hi,

If you face like me some issue for no data received from the Smarty, this is a workaround that may help. Disclamer: It's my 1st experience in ESP, C++, MQTT, Home Assistant, and many other stuff... so please be kind ^^

Since the firmware upgrade of my Smarty (to get 3 phases values), Sam did a great work to adapt the firmware.

Since this Smarty upgrade, I got random no value received from couple of minutes to days on my MQTT broker. Almost of the time, I got to unplug/plug the Smarty module board from the Smarty counter to get it working back.

I spent quite a lot of time to understand what was happening but I didn't get the exact reason... (network, power, esp issue). At the end, the debug was still showing me "no data received" and restart after 10 tries as set in the code didn't unfortunately help. So I focus on a workaround and I found one that works! :D

The idea was to use the deepSleep mode feature of the D1 Mini Pro and it makes a "real" hard reset on wake.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Carefull, the deepSleep mode required to connect D0(GPIO16) <>RST on the D1 Mini Pro. But once connected, you can't flash anymore. I highly recommand to use a jumper. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

1st, I updated the firmware of Sam to get mqtt received features that was not required until now in smartyreader.ino and subscribe to a topic called "smarty/#". My published topic is still set to "lamsmarty/#"

void onMqttConnect(bool sessionPresent) {
  DEBUG_PRINTLN("Connected to MQTT.");
  DEBUG_PRINT("Session present: ");
  DEBUG_PRINTLN(sessionPresent);

  uint16_t packetIdSub = mqttClient.subscribe("smarty/#", 0);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub);

  start_publishing_dsmr_units();
}

and

void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
  DEBUG_PRINTLN("Subscribe acknowledged.");
  DEBUG_PRINT("  packetId: ");
  DEBUG_PRINTLN(packetId);
  DEBUG_PRINT("  qos: ");
  DEBUG_PRINTLN(qos);
}

void onMqttUnsubscribe(uint16_t packetId) {
  DEBUG_PRINTLN("Unsubscribe acknowledged.");
  DEBUG_PRINT("  packetId: ");
  DEBUG_PRINTLN(packetId);
}

void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
  DEBUG_PRINTLN("Publish received.");
  DEBUG_PRINT("  topic: ");
  DEBUG_PRINTLN(topic);
  DEBUG_PRINT("  qos: ");
  DEBUG_PRINTLN(properties.qos);
  DEBUG_PRINT("  dup: ");
  DEBUG_PRINTLN(properties.dup);
  DEBUG_PRINT("  retain: ");
  DEBUG_PRINTLN(properties.retain);
  DEBUG_PRINT("  len: ");
  DEBUG_PRINTLN(len);
  DEBUG_PRINT("  index: ");
  DEBUG_PRINTLN(index);
  DEBUG_PRINT("  total: ");
  DEBUG_PRINTLN(total);

Then I used this action for the D1 Mini Pro to enter in deepSleep after 30s when the topic "smarty/deepsleep" is sent to my MQTT broker

  //Deepsleep for 30s on received MQTT message from HomeAssistant MQTT broker
  // Check if the MQTT message was received on topic smarty/deepsleep
  if (strcmp(topic,"smarty/deepsleep") == 0) {
  DEBUG_PRINTLN("Deepsleep for 30s requested");
  ESP.deepSleep(30e6);
  }

Then I set a kind of watchdog sensor in Home Assistant (that I use now instead of nodered) where smarty_check" is a history graph and smarty_binary a status (false/true).

        smarty_check:
          friendly_name: "Smarty check"
          unit_of_measurement: "Seconds"
          value_template: "{{ (now() - states.sensor.power_delivered.last_updated ).total_seconds() }}"

        smarty_binary:
          friendly_name: "Smarty binary"
          value_template: "{{ (now() - states.sensor.power_delivered.last_updated ).total_seconds() > 30 }}"

Then, still form Home Assistant, I created this automation to send the "magic" topic to deepsleep/hardreset the D1 and to get a notification on my smartphone if the Smarty/D1 Mini Pro do not provide data after 2 minutes.

- id: '1618164423737'
  alias: Notify and restart Smarty
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.smarty_binary
    from: 'False'
    to: 'True'
    for: 00:02:00
  condition: []
  action:
  - device_id: e21cdac2219581b0571fc0be730ec685
    domain: mobile_app
    type: notify
    title: 'Smarty unavailable for 2 min, deepSleep has been activated '
    message: The smarty restarted
  - service: mqtt.publish
    data:
      topic: 'smarty/deepsleep'
  mode: single

That's it and I hope it could help of someone that is facing the same issue.

Also the deepsleep mode automation could be directly integrated in the firmware I suppose. Then no need specific yaml code in Home Assistant. I will try to do that later, it should be quite easy now.

Don't hesitate to ask for more info.

Thanks for reading. And also to Sam for his continous support to get this workaround alive!

Cheers!

Julien

sgrimee commented 3 years ago

thanks @piltous for all your research and finding a workaround to reset the device properly with deepsleep.

Indeed it would be great to include this in the firmware so that the MQTT received code is not needed (I used to have it before, removed it but cannot remember why) and no dependency on an external automation.

In case you get there, I would welcome a merge request for the code change and documentation. I might look into it myself later because I also have the same problem, but no time at the moment so it may take a while.

thanks again!

piltous commented 3 years ago

Thank you for the warm feedback Sam. I will make some tentatives of integretion for sure (I still need to play...) but nothing urgent for now or if someone asks. Never give up :)