tjhowse / modbus4mqtt

Modbus TCP <-> MQTT glue. YAML configuration. Robust.
Other
77 stars 34 forks source link

[feature request] ModBus Connection status #61

Open r-xyz opened 1 day ago

r-xyz commented 1 day ago

Dear @tjhowse , Thanks for this nice piece of software. :)

I would like to improve the information regarding modbus connection status. This might help to use it as availability topics, as well as enabling clients to detect failures directly from MQTT data. Before proceeding to a PR (if the repository is still active) I would like to check with you the best way to implement this.

Current status

  1. On startup, the software attempts in sequence:
    1. Mobdus connection: if it fails, the system logs an error and exits. No failure message is published to MQTT.
    2. If the above succeeds, MQTT connection is attempted.
      1. If this fails due to auth problems, the system will keep retrying the connection.
      2. If an exception occurs (e.g. hostname do not resolve), the program exits with error.
      3. If all is ok, modbus4mqtt v connected is published under <prefix>/modbus4mqtt .
  2. No message is published on disconnection
  3. No message is published if -once initially connected- Modbus fail to poll registries or fails to reconnect.

Suggested solutions (feedback welcome)

  1. Add last will message to notify MQTT disconnection (or program failing/being terminated and not running anymore) This should cover both n. 1.ii.a and 2. It could be done by adding the following before calling connect() on MQTT client. Content can actually be changed to just an empty string.
    self._mqtt_client.will_set(self.prefix+'modbus4mqtt', 'modbus4mqtt v{} disconnected.'.format(version.version))
  2. Add additional topic to notify n. 3. It can be something like:
    • At the end of connect_modbus (successful connection), adding a conditional statement to check that MQTT is connected.
      self._mqtt_client.will_set(self.prefix+'modbus', 'online')
    • on poll() failure:
      self._mqtt_client.will_set(self.prefix+'modbus', 'offline')
  3. Consider swapping connect_modbus() and connect_mqtt() at startup to avoid the extra conditional above. Not sure about implications.
  4. Consider adding retain flag to both self.prefix+'modbus'and self.prefix+'modbus4mqtt'

Looking forward for any feedback to contribute. Thanks in advance.

pki791 commented 1 day ago

Hi, you can look into my fork, i added a timestamp to each message and i use it to che k if the data is fresh 😁

tjhowse commented 1 day ago

Hi @r-xyz ,

Those improvements all seem very reasonable! However I would suggest a few small changes:

Item 2: It is possible that an existing user has defined a register named "modbus" and that would conflict with the proposed online/offline status message. I would suggest publishing these messages to <prefix>/modbus4mqtt/modbus_status, or something similar. Also, the status message contents could provide a timestamp, as @pki791 has done, to ensure a stale online message can be detected by a consumer of the message? Perhaps a message like {"status": "online", "timestamp": "2024-09-24T01:23:45Z"}?

Item 3: Could you please explain the benefits of this change in more detail?

I'm assuming the will_set() calls in the online/offline code snippets are just a typo? Should they be publish()?

Please note that the best PRs tick the following boxes:

These help keep a FOSS project humming along smoothly.

Cheers, tjhowse.

r-xyz commented 9 hours ago

Hi @tjhowse and @pki791 , Thanks for the feedback.

Following up: Item 1: OK Item 2:

Item 3:

Item 4:

Will hopefully send a PR in the upcoming days. Cheers, r-xyz

r-xyz commented 8 hours ago

If you prefer, I can also change modbus4mqtt message to JSON like that


{"status": "offline/online", "version":  "v0.7.0","timestamp": "2024-09-24T01:23:45Z"}