Browse Source

2023-08-28:
- enable/disable actions from received remote commands via MQTT (i.E. to switch that from Home Assistant when no one is in the house etc.)
see comment in cul2mqtt_example.ini for details

FloKra 8 months ago
parent
commit
593d90fe62
4 changed files with 103 additions and 2 deletions
  1. 4 0
      CHANGELOG.txt
  2. 8 0
      HomeAssistant_CUL2MQTT.yaml
  3. 80 2
      cul2mqtt.py
  4. 11 0
      cul2mqtt_example.ini

+ 4 - 0
CHANGELOG.txt

@@ -1,3 +1,7 @@
+2023-08-28:
+ - enable/disable actions from received remote commands via MQTT (i.E. to switch that from Home Assistant when no one is in the house etc.)
+   see comment in cul2mqtt_example.ini for details
+
 2023-08-28:
  - option to log successfully received commands (from configured/known senders) while keeping debug logging disabled
  

+ 8 - 0
HomeAssistant_CUL2MQTT.yaml

@@ -0,0 +1,8 @@
+- name: "CUL2MQTT - Enable Received Actions"
+  state_topic: "CUL2MQTT/state/turnOnActions"
+  command_topic: "CUL2MQTT/control/turnOnActions"
+  qos: 1
+  payload_on: "ON"
+  payload_off: "OFF"
+  retain: true
+  icon: mdi:remote

+ 80 - 2
cul2mqtt.py

@@ -52,6 +52,16 @@ mqtt_port = config['mqtt'].getint('port')
 mqtt_user = config['mqtt'].get('user')
 mqtt_password = config['mqtt'].get('password')
 
+
+# MQTT Control
+enableMQTTControl = config['main'].getboolean('enableMQTTControl')
+MQTT_Control_Topic_turnOnActions = config['main'].get('MQTT_Control_Topic_turnOnActions')
+MQTT_Control_StateTopic = config['main'].get('MQTT_Control_StateTopic')
+
+turnOnActions = True
+if enableMQTTControl:
+    turnOnActions = False
+
 TX_interface_prefer = config['cul'].get('TX_interface_prefer') # UART or MQTT
 if TX_interface_prefer is None: # compatibility with old ini file structure
     TX_interface_prefer = config['main'].get('TX_interface_prefer') # UART or MQTT
@@ -334,6 +344,50 @@ lastSentDevCmd = ""
 def touch(fname, times=None):
     with open(fname, 'a'):
         os.utime(fname, times)
+        
+def turnOnActions_enable():
+    global turnOnActions
+    turnOnActions = True
+    log_write("")
+    log_write("MQTT control: switched turnOnActions to ON")
+    mqttc.publish(MQTT_Control_StateTopic + "/turnOnActions", "ON", qos=0, retain=True)
+    try:
+        turnOnActions_file = open("turnOnActions", "w")
+        turnOnActions_file.write("ON")
+        turnOnActions_file.close()
+    except:
+        log_write("ERROR: could not write turnOnActions state to file.")
+
+def turnOnActions_disable():
+    global turnOnActions
+    turnOnActions = False
+    log_write("")
+    log_write("MQTT control: switched turnOnActions to OFF")
+    mqttc.publish(MQTT_Control_StateTopic + "/turnOnActions", "OFF", qos=0, retain=True)
+    try:
+        turnOnActions_file = open("turnOnActions", "w")
+        turnOnActions_file.write("OFF")
+        turnOnActions_file.close()
+    except:
+        log_write("ERROR: could not write turnOnActions state to file.")
+
+def turnOnActions_get():
+    global turnOnActions
+    try:
+        turnOnActions_file = open("turnOnActions", "r")
+        _content = turnOnActions_file.read()
+        turnOnActions_file.close()
+        
+        log_write("MQTT control: restored last state of turnOnActions from file")
+        if _content == "ON":
+            turnOnActions = True
+            log_write("MQTT control: switched turnOnActions to ON")
+        elif _content == "OFF":
+            turnOnActions = True
+            log_write("MQTT control: switched turnOnActions to OFF")
+    except:
+        log_write("ERROR: could not read turnOnActions state from file.")
+    
 
 def on_connect(client, userdata, flags, rc):
     if verbose:
@@ -351,12 +405,20 @@ def on_connect(client, userdata, flags, rc):
             client.subscribe(in_topic)
             if verbose:
                 log_write("MQTT subscribed: " + in_topic)
+                
+    # MQTT control
+    if enableMQTTControl:
+        if MQTT_Control_Topic_turnOnActions != "":
+            client.subscribe(MQTT_Control_Topic_turnOnActions)
+            if verbose:
+                log_write("MQTT subscribed: " + MQTT_Control_Topic_turnOnActions)
 
 def on_disconnect(client, userdata, rc):
     if rc != 0:
         log_write("Unexpected MQTT disconnection. Will auto-reconnect")
         
 def on_message(client, userdata, msg):
+    global turnOnActions
     #print(msg.topic + ": " + str(msg.payload))
     payload = msg.payload.decode("utf-8")
     
@@ -364,8 +426,15 @@ def on_message(client, userdata, msg):
         log_write("")
         log_write("MQTT received: " + msg.topic + " -> " + str(payload))
     
+    # MQTT message is for control
+    if enableMQTTControl and msg.topic == MQTT_Control_Topic_turnOnActions:
+        if payload == "ON" or payload == "on" or payload == "true" or payload == "1":
+            turnOnActions_enable()
+        elif payload == "OFF" or payload == "off" or payload == "false" or payload == "0":
+            turnOnActions_disable()
+        
     # MQTT message is output from CUL
-    if receive_from_mqtt_cul and msg.topic == mqtt_cul_topic_received:
+    elif receive_from_mqtt_cul and msg.topic == mqtt_cul_topic_received:
         payload = payload.rstrip()
             
         # support output from Tasmota SerialBridge on tele/[DEVICE]/RESULT topic
@@ -415,7 +484,8 @@ def on_message(client, userdata, msg):
 
                     
 def publish_device_statusupdate(device, cmd, value):
-    if device in devdata.keys():
+    global turnOnActions
+    if turnOnActions and device in devdata.keys():
         if 'statTopic' in devdata[device].keys():
             statTopic = devdata[device].get('statTopic')
             
@@ -997,6 +1067,14 @@ mqttc.on_connect = on_connect
 mqttc.on_disconnect = on_disconnect
 mqttc.on_message = on_message
 
+if enableMQTTControl:
+    turnOnActions_get()
+    log_write("")
+    log_write("MQTT-control is enabled.")
+    log_write("to enable any actions you must send 'ON' to MQTT-topic: '" + MQTT_Control_Topic_turnOnActions + "'")
+    log_write("")
+    log_write("")
+
 if mqtt_user is not None and mqtt_password is not None:
     if len(mqtt_user) > 0 and len(mqtt_password) > 0:
         mqttc.username_pw_set(mqtt_user, mqtt_password)

+ 11 - 0
cul2mqtt_example.ini

@@ -23,6 +23,17 @@ dataReceiveTimeout = 180
 # ONLY set this to a location in a RAM drive!!! (i.E. /tmp/cul2mqtt_lastReceived on RaspberryOS or /run/user/XXXX/cul2mqtt_lastReceived where XXXX is the user id)
 lastReceivedStatusFile = /run/user/1000/cul2mqtt_lastReceived
 
+# control (switch on/off) parsing and actions (MQTT publishing) via MQTT command
+# if enabled, you must send "ON" (or "OFF") to the configured "MQTT_Control_Topic_turnOnActions" topic
+# this can be used to switch it off and on from Home Assistant while keeping sending of codes working
+# -> ON/OFF command should be sent RETAINED in order to always work!!!
+# the current state is published on "MQTT_Control_StateTopic"/[commandName] on every change
+# i.E.: CUL2MQTT/state/turnOnActions -> ON/OFF
+# the state is also saved in a file (in script directory) and recovered on next start
+# see HomeAssistant_CUL2MQTT.yaml to see how to integrate it in Home Assistant
+enableMQTTControl = false
+MQTT_Control_Topic_turnOnActions = CUL2MQTT/control/turnOnActions
+MQTT_Control_StateTopic = CUL2MQTT/state
 
 [cul]
 serialPort = /dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0