mqtt-flora.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #!/usr/bin/env python3
  2. import sys
  3. import json
  4. from time import sleep, localtime, strftime
  5. from configparser import ConfigParser
  6. from miflora.miflora_poller import MiFloraPoller, MI_BATTERY, MI_CONDUCTIVITY, MI_LIGHT, MI_MOISTURE, MI_TEMPERATURE
  7. import paho.mqtt.client as mqtt
  8. parameters = [MI_BATTERY, MI_CONDUCTIVITY, MI_LIGHT, MI_MOISTURE, MI_TEMPERATURE]
  9. print('Xiaomi Mi Flora Plant Sensor MQTT Client/Daemon')
  10. print('Source: https://github.com/janwh/miflora-mqtt-daemon')
  11. print()
  12. # Load configuration file
  13. config = ConfigParser(delimiters=('=', ))
  14. config.optionxform = str
  15. config.read('config.ini')
  16. daemon_enabled = config['Daemon'].getboolean('enabled', True)
  17. sleep_period = config['Daemon'].getint('period', 60)
  18. topic_prefix = config['MQTT'].get('topic_prefix', 'miflora')
  19. miflora_cache_timeout = config['MiFlora'].getint('cache_timeout', 600)
  20. if not config['Sensors']:
  21. print('Error. Please add at least one sensor to the configuration file "config.ini".', file=sys.stderr)
  22. print('Scan for available Miflora sensors with "hcitool lescan".', file=sys.stderr)
  23. sys.exit(1)
  24. # Initialize Mi Flora sensors
  25. flores = {}
  26. for flora in config['Sensors'].items():
  27. print('Adding device from config to Mi Flora device list ...')
  28. print('Name: "{}"'.format(flora[0]))
  29. flores[flora[0]] = MiFloraPoller(mac=flora[1], cache_timeout=miflora_cache_timeout)
  30. print('Device name: "{}"'.format(flores[flora[0]].name()))
  31. print('MAC address: {}'.format(flora[1]))
  32. print('Firmware: {}'.format(flores[flora[0]].firmware_version()))
  33. print()
  34. # Callbacks http://www.eclipse.org/paho/clients/python/docs/#callbacks
  35. def on_connect(client, userdata, flags, rc):
  36. if rc != 0:
  37. print('Connected with result code {}: {}'.format(str(rc), mqtt.connack_string(rc)), file=sys.stderr)
  38. sys.exit(1)
  39. def on_publish(client, userdata, mid):
  40. print('Data successfully published!')
  41. # MQTT connection
  42. print('Connecting to MQTT broker ...')
  43. mqtt_client = mqtt.Client()
  44. mqtt_client.on_connect = on_connect
  45. mqtt_client.on_publish = on_publish
  46. if config['MQTT'].get('username'):
  47. mqtt_client.username_pw_set(config['MQTT'].get('username'), config['MQTT'].get('password', None))
  48. try:
  49. mqtt_client.connect(config['MQTT'].get('hostname', 'localhost'),
  50. port=config['MQTT'].getint('port', 1883),
  51. keepalive=config['MQTT'].getint('keepalive', 60))
  52. except:
  53. print('Error. Please check your MQTT connection settings in the configuration file "config.ini".', file=sys.stderr)
  54. sys.exit(1)
  55. else:
  56. print('Connected.\n')
  57. mqtt_client.loop_start()
  58. # Sensor data retrieval and publishing
  59. while True:
  60. for flora in flores:
  61. data = {}
  62. for param in parameters:
  63. data[param] = flores.get(flora).parameter_value(param)
  64. print(strftime('[%Y-%m-%d %H:%M:%S]', localtime()), end=' ')
  65. print('Attempting to publishing to MQTT topic "{}/{}" ...\nData: {}'.format(topic_prefix, flora, json.dumps(data)))
  66. mqtt_client.publish('{}/{}'.format(topic_prefix, flora), json.dumps(data))
  67. sleep(0.5) # some slack for the publish roundtrip and callback function
  68. print()
  69. if not daemon_enabled:
  70. break
  71. print('Sleeping ({} seconds) ...'.format(sleep_period))
  72. sleep(sleep_period)
  73. print()
  74. mqtt_client.disconnect()