.
This commit is contained in:
@@ -130,8 +130,9 @@ class MqttConfigMessage(MqttMessage):
|
||||
BINARY_SENSOR = 'binary_sensor'
|
||||
|
||||
def __init__(self, component, name, payload=None, retain=False):
|
||||
if 'name' not in payload: payload['name'] = name
|
||||
super().__init__("{}/{}/config".format(component, name), json.dumps(payload), retain)
|
||||
# if 'name' not in payload: payload['name'] = name
|
||||
# super().__init__("{}/{}/config".format(component, name), json.dumps(payload), retain)
|
||||
super().__init__("{}/{}".format(component, name), payload, retain)
|
||||
|
||||
@property
|
||||
def retain(self):
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
from builtins import staticmethod
|
||||
import logging
|
||||
|
||||
from mqtt import MqttMessage, MqttConfigMessage
|
||||
|
||||
from workers.base import BaseWorker
|
||||
import logger
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import time
|
||||
|
||||
|
||||
|
||||
REQUIREMENTS = ['python-eq3bt']
|
||||
monitoredAttrs = ["low_battery", "valve_state", "target_temperature", "window_open", "locked"]
|
||||
_LOGGER = logger.get(__name__)
|
||||
|
||||
|
||||
|
||||
STATE_AWAY = 'away'
|
||||
STATE_BOOST = 'boost'
|
||||
STATE_AUTO = 'auto'
|
||||
STATE_MANUAL = 'manual'
|
||||
STATE_ON = 'on'
|
||||
STATE_OFF = 'off'
|
||||
|
||||
|
||||
|
||||
class Eq3BtWorker(BaseWorker):
|
||||
class ModesMapper():
|
||||
def __init__(self):
|
||||
from eq3bt import Mode
|
||||
|
||||
self._mapped_modes = {
|
||||
Mode.Closed: STATE_OFF,
|
||||
Mode.Open: STATE_ON,
|
||||
Mode.Auto: STATE_AUTO,
|
||||
Mode.Manual: STATE_MANUAL,
|
||||
Mode.Away: STATE_AWAY,
|
||||
Mode.Boost: STATE_BOOST,
|
||||
}
|
||||
|
||||
self._reverse_modes = {v: k for k, v in self._mapped_modes.items()}
|
||||
|
||||
def get_mapping(self, mode):
|
||||
if mode < 0:
|
||||
return None
|
||||
return self._mapped_modes[mode]
|
||||
|
||||
def get_reverse_mapping(self, mode):
|
||||
return self._reverse_modes[mode]
|
||||
|
||||
|
||||
|
||||
def format_topic(self, *args, separator='/'):
|
||||
return separator.join([*args])
|
||||
|
||||
|
||||
|
||||
def mqttHomieDevice(self,device, name, nodes):
|
||||
return [
|
||||
MqttConfigMessage(self.format_topic(device), "$state", payload="ready"),
|
||||
MqttConfigMessage(self.format_topic(device), "$homie", payload="3.0"),
|
||||
MqttConfigMessage(self.format_topic(device), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(device), "$nodes", payload=nodes)
|
||||
]
|
||||
|
||||
|
||||
|
||||
def mqttHomieNode(self, device, label, name, properties):
|
||||
return [
|
||||
MqttConfigMessage(self.format_topic(device, label), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(device, label), "$properties", payload=properties),
|
||||
]
|
||||
|
||||
|
||||
|
||||
def mqttHomieProperty(self, device, node, prop, name, dtype, settable = False, retained = False, unit = None, dformat = None):
|
||||
retval = [
|
||||
MqttConfigMessage(self.format_topic(device, node, prop), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(device, node, prop), "$datatype", payload=dtype),
|
||||
MqttConfigMessage(self.format_topic(device, node, prop), "$settable", payload="true" if settable else "false"),
|
||||
MqttConfigMessage(self.format_topic(device, node, prop), "$retained", payload="true" if retained else "false")
|
||||
]
|
||||
if unit is not None:
|
||||
retval.append(MqttConfigMessage(self.format_topic(device, node, prop), "$unit", payload=unit))
|
||||
if dformat is not None:
|
||||
retval.append(MqttConfigMessage(self.format_topic(device, node, prop), "$format", payload=dformat))
|
||||
return retval
|
||||
|
||||
|
||||
|
||||
def _setup(self):
|
||||
from eq3bt import Thermostat
|
||||
|
||||
_LOGGER.info("Adding %d %s devices", len(self.devices), repr(self))
|
||||
for name, mac in self.devices.items():
|
||||
_LOGGER.debug("Adding %s device '%s' (%s)", repr(self), name, mac)
|
||||
self.devices[name] = {"mac": mac, "thermostat": Thermostat(mac)}
|
||||
|
||||
self._modes_mapper = self.ModesMapper()
|
||||
self._command_queue = []
|
||||
|
||||
|
||||
|
||||
def config(self):
|
||||
ret = []
|
||||
for name, data in self.devices.items():
|
||||
ret += self.config_device(name, data["mac"])
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
def config_device(self, name, mac):
|
||||
from eq3bt import eq3btsmart
|
||||
_LOGGER.debug("Configuring device " + str(name))
|
||||
retval = []
|
||||
retval = self.mqttHomieDevice(name, "Smart Thermostat: " + str(name) + " (" + str(mac)+ ")", "status,climate")
|
||||
|
||||
retval += self.mqttHomieNode(name, "status", "Device Status", "low_battery,window_open,locked,last_updated")
|
||||
retval += self.mqttHomieProperty(name, "status", "low_battery", "Low Battery", "boolean", False, True)
|
||||
retval += self.mqttHomieProperty(name, "status", "window_open", "Window Open", "boolean", False, True)
|
||||
retval += self.mqttHomieProperty(name, "status", "locked", "Lock", "boolean", True, True)
|
||||
retval += self.mqttHomieProperty(name, "status", "last_updated", "Last Updated", "string", False, True)
|
||||
|
||||
retval += self.mqttHomieNode(name, "climate", "Climate Control", "mode,target_temperature,comfort_temperature,eco_temperature,temperature_offset,valve_state")
|
||||
retval += self.mqttHomieProperty(name, "climate", "mode", "Climate Mode", "enum", True, True, dformat = "auto,manual,boost,away,on,off")
|
||||
retval += self.mqttHomieProperty(name, "climate", "target_temperature", "Target Temperature", "float", True, True, dformat = str(eq3btsmart.EQ3BT_MIN_TEMP) + ":" + str(eq3btsmart.EQ3BT_MAX_TEMP))
|
||||
retval += self.mqttHomieProperty(name, "climate", "comfort_temperature", "Comfort Temperature", "float", True, True, dformat = str(eq3btsmart.EQ3BT_MIN_TEMP) + ":" + str(eq3btsmart.EQ3BT_MAX_TEMP))
|
||||
retval += self.mqttHomieProperty(name, "climate", "eco_temperature", "ECO Temperature", "float", True, True, dformat = str(eq3btsmart.EQ3BT_MIN_TEMP) + ":" + str(eq3btsmart.EQ3BT_MAX_TEMP))
|
||||
retval += self.mqttHomieProperty(name, "climate", "temperature_offset", "Temperature Offset", "float", True, True)
|
||||
retval += self.mqttHomieProperty(name, "climate", "valve_state", "Valve State", "integer", False, True)
|
||||
|
||||
return retval
|
||||
|
||||
|
||||
|
||||
def run(self, mqtt):
|
||||
_LOGGER.info("Starting eq3bt daemon")
|
||||
from bluepy import btle
|
||||
self.time_next_update = datetime.now()
|
||||
commandTryCounter = 0
|
||||
updateTryCounter = 0
|
||||
while True:
|
||||
try:
|
||||
time_now = datetime.now()
|
||||
|
||||
if time_now > self.time_next_update:
|
||||
_LOGGER.info("Updating %d %s devices", len(self.devices), repr(self))
|
||||
updateTryCounter += 1
|
||||
if updateTryCounter <= 3:
|
||||
for name, data in self.devices.items():
|
||||
_LOGGER.debug("Updating %s device '%s' (%s)", repr(self), name, data["mac"])
|
||||
ret = self.update_device_state(name, data["thermostat"])
|
||||
mqtt.publish(ret)
|
||||
_LOGGER.debug("Updating %s device '%s' finished", repr(self), name)
|
||||
updateTryCounter -= 1
|
||||
else:
|
||||
_LOGGER.error("Retried update too many times, dropping for now...")
|
||||
updateTryCounter = 0
|
||||
self.time_next_update = time_now + timedelta(seconds=self.update_interval)
|
||||
|
||||
if len(self._command_queue) > 0:
|
||||
_LOGGER.info("Executing command")
|
||||
commandTryCounter += 1
|
||||
if commandTryCounter <= 5:
|
||||
command = self._command_queue[0]
|
||||
if command():
|
||||
self.time_next_update = time_now
|
||||
del self._command_queue[0]
|
||||
commandTryCounter -= 1
|
||||
_LOGGER.debug("Executing command finished")
|
||||
else:
|
||||
_LOGGER.error("Retried command too many times, dropping command...")
|
||||
del self._command_queue[0]
|
||||
commandTryCounter = 0
|
||||
|
||||
time.sleep(1.0)
|
||||
|
||||
except btle.BTLEException as e:
|
||||
import traceback
|
||||
_LOGGER.error("Caught BTLEException: {}".format(e))
|
||||
_LOGGER.error(traceback.format_exc())
|
||||
import subprocess
|
||||
_LOGGER.error("Reseting hci0")
|
||||
try:
|
||||
subprocess.run(["/bin/hciconfig", "hci0", "down"], timeout=10)
|
||||
time.sleep(1.0)
|
||||
subprocess.run(["/bin/hciconfig", "hci0", "up"], timeout=10)
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception while reseting hci0: {}".format(e))
|
||||
_LOGGER.error(traceback.format_exc())
|
||||
time.sleep(10.0)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
_LOGGER.error("Caught exception in Eq3BtWorker.run(): {}".format(e))
|
||||
_LOGGER.error(traceback.format_exc())
|
||||
time.sleep(1.0)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'''
|
||||
def status_update(self):
|
||||
from bluepy import btle
|
||||
|
||||
ret = []
|
||||
_LOGGER.info("Updating %d %s devices", len(self.devices), repr(self))
|
||||
for name, data in self.devices.items():
|
||||
_LOGGER.debug("Updating %s device '%s' (%s)", repr(self), name, data["mac"])
|
||||
try:
|
||||
ret += self.update_device_state(name, data["thermostat"])
|
||||
except btle.BTLEException as e:
|
||||
logger.log_exception(_LOGGER, "Error during update of %s device '%s' (%s): %s", repr(self), name, data["mac"], type(e).__name__, suppress=True)
|
||||
|
||||
_LOGGER.info("Updating %d %s devices finshed", len(self.devices), repr(self))
|
||||
return ret
|
||||
'''
|
||||
|
||||
|
||||
|
||||
def on_command(self, topic, value):
|
||||
retval = []
|
||||
try:
|
||||
value = value.decode('utf-8')
|
||||
device_name, nodename, propname, operation = topic.split('/')
|
||||
_LOGGER.debug("Command \"%s\", on %s.%s.%s: %s", operation, device_name, nodename, propname, value)
|
||||
device = self.devices[device_name]["thermostat"]
|
||||
|
||||
def _cmd_fun():
|
||||
if propname == "locked" and operation == "set":
|
||||
device.locked = True
|
||||
elif value == "false" or value == "off":
|
||||
device.locked = False
|
||||
elif propname == "mode" and operation == "set":
|
||||
device.mode = self._modes_mapper.get_reverse_mapping(value)
|
||||
elif propname == "target_temperature" and operation == "set":
|
||||
device.target_temperature = float(value)
|
||||
elif propname == "comfort_temperature" and operation == "set":
|
||||
device.comfort_temperature = float(value)
|
||||
elif propname == "eco_temperature" and operation == "set":
|
||||
device.eco_temperature = float(value)
|
||||
elif propname == "temperature_offset" and operation == "set":
|
||||
device.temperature_offset = float(value)
|
||||
elif propname == "valve_state" and operation == "set":
|
||||
device.valve_state = float(value)
|
||||
return True
|
||||
|
||||
self._command_queue.append(_cmd_fun)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
_LOGGER.error("Caught exception in Eq3BtWorker.on_command(): {}".format(e))
|
||||
_LOGGER.error(traceback.format_exc())
|
||||
return retval
|
||||
|
||||
|
||||
|
||||
def update_device_state(self, name, thermostat):
|
||||
from datetime import datetime
|
||||
thermostat.update()
|
||||
ret = []
|
||||
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'status', 'low_battery'), payload="true" if thermostat.low_battery else "false"))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'status', 'window_open'), payload="true" if thermostat.window_open else "false"))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'status', 'locked'), payload="true" if thermostat.locked else "false"))
|
||||
|
||||
ha_mode = self._modes_mapper.get_mapping(thermostat.mode)
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'climate', 'mode'), payload=ha_mode))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'climate', 'target_temperature'), payload=thermostat.target_temperature))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'climate', 'comfort_temperature'), payload=thermostat.comfort_temperature))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'climate', 'eco_temperature'), payload=thermostat.eco_temperature))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'climate', 'temperature_offset'), payload=thermostat.temperature_offset))
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'climate', 'valve_state'), payload=thermostat.valve_state))
|
||||
|
||||
ret.append(MqttMessage(topic=self.format_topic(name, 'status', 'last_updated'), payload=datetime.isoformat(datetime.now())))
|
||||
|
||||
return ret
|
||||
@@ -0,0 +1,98 @@
|
||||
from mqtt import MqttMessage, MqttConfigMessage
|
||||
|
||||
from workers.base import BaseWorker
|
||||
import logger
|
||||
import subprocess
|
||||
import traceback
|
||||
|
||||
REQUIREMENTS = []
|
||||
_LOGGER = logger.get(__name__)
|
||||
|
||||
|
||||
class LinuxhostWorker(BaseWorker):
|
||||
|
||||
def mqttHomieDevice(self, name, nodes):
|
||||
return [
|
||||
MqttConfigMessage(self.format_topic(), "$state", payload="ready"),
|
||||
MqttConfigMessage(self.format_topic(), "$homie", payload="3.0"),
|
||||
MqttConfigMessage(self.format_topic(), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(), "$nodes", payload=nodes)
|
||||
]
|
||||
|
||||
|
||||
def mqttHomieNode(self, label, name, properties):
|
||||
return [
|
||||
MqttConfigMessage(self.format_topic(label), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(label), "$properties", payload=properties),
|
||||
]
|
||||
|
||||
|
||||
def mqttHomieProperty(self, node, prop, name, dtype, settable = False, retained = False, unit = None, dformat = None):
|
||||
retval = [
|
||||
MqttConfigMessage(self.format_topic(node, prop), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(node, prop), "$datatype", payload=dtype),
|
||||
MqttConfigMessage(self.format_topic(node, prop), "$settable", payload="true" if settable else "false"),
|
||||
MqttConfigMessage(self.format_topic(node, prop), "$retained", payload="true" if retained else "false")
|
||||
]
|
||||
if unit is not None:
|
||||
retval.append(MqttConfigMessage(self.format_topic(node, prop), "$unit", payload=unit))
|
||||
if dformat is not None:
|
||||
retval.append(MqttConfigMessage(self.format_topic(node, prop), "$format", payload=dformat))
|
||||
return retval
|
||||
|
||||
|
||||
def _setup(self):
|
||||
pass
|
||||
|
||||
|
||||
def config(self):
|
||||
_LOGGER.debug("Configuring")
|
||||
retval = self.mqttHomieDevice("Linux Host", "xserver")
|
||||
retval += self.mqttHomieNode("xserver", "XServer", "screensaver")
|
||||
retval += self.mqttHomieProperty("xserver", "screensaver", "Screensaver", "enum", True, False, dformat="activate,deactivate")
|
||||
return retval
|
||||
|
||||
|
||||
def status_update(self):
|
||||
retval = []
|
||||
try:
|
||||
pass
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception in LinuxhostWorker.status_update(): {}".format(e))
|
||||
traceback.print_exc();
|
||||
return retval
|
||||
|
||||
|
||||
def on_command(self, topic, value):
|
||||
retval = []
|
||||
try:
|
||||
value = value.decode('utf-8')
|
||||
_, nodename, propname, operation = topic.split('/')
|
||||
_LOGGER.debug("Command \"%s\", on %s.%s: %s", operation, nodename, propname, value)
|
||||
if propname == "screensaver" and operation == "set":
|
||||
if value == "activate" and self._enableScreensaver() == 0:
|
||||
retval.append(MqttMessage(topic=self.format_topic("xserver", "screensaver"), payload="activate", retain=False))
|
||||
elif value == "deactivate" and self._disableScreensaver() == 0:
|
||||
retval.append(MqttMessage(topic=self.format_topic("xserver", "screensaver"), payload="deactivate", retain=False))
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception in LinuxhostWorker.on_command(): {}".format(e))
|
||||
traceback.print_exc();
|
||||
return retval
|
||||
|
||||
|
||||
def _enableScreensaver(self):
|
||||
try:
|
||||
_LOGGER.info('Enable Screensaver')
|
||||
return subprocess.call("DISPLAY=:0.0 sudo -u pi /usr/bin/xscreensaver-command -activate", shell=True)
|
||||
except Exception as e:
|
||||
logging.error("Caught Exception in LinuxhostWorker.enableScreensaver: " + str(e))
|
||||
return -1
|
||||
|
||||
|
||||
def _disableScreensaver(self):
|
||||
try:
|
||||
_LOGGER.info('Disable Screensaver')
|
||||
return subprocess.call("DISPLAY=:0.0 sudo -u pi /usr/bin/xscreensaver-command -deactivate", shell=True)
|
||||
except Exception as e:
|
||||
logging.error("Caught Exception in LinuxhostWorker.disableScreensaver: " + str(e))
|
||||
return -1
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
from mqtt import MqttMessage, MqttConfigMessage
|
||||
|
||||
from workers.base import BaseWorker
|
||||
import logger
|
||||
import subprocess
|
||||
import traceback
|
||||
|
||||
REQUIREMENTS = []
|
||||
_LOGGER = logger.get(__name__)
|
||||
|
||||
|
||||
class MpdWorker(BaseWorker):
|
||||
|
||||
def mqttHomieDevice(self, name, nodes):
|
||||
return [
|
||||
MqttConfigMessage(self.format_topic(), "$state", payload="ready"),
|
||||
MqttConfigMessage(self.format_topic(), "$homie", payload="3.0"),
|
||||
MqttConfigMessage(self.format_topic(), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(), "$nodes", payload=nodes)
|
||||
]
|
||||
|
||||
|
||||
def mqttHomieNode(self, label, name, properties):
|
||||
return [
|
||||
MqttConfigMessage(self.format_topic(label), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(label), "$properties", payload=properties),
|
||||
]
|
||||
|
||||
|
||||
def mqttHomieProperty(self, node, prop, name, dtype, settable = False, retained = False, unit = None, dformat = None):
|
||||
retval = [
|
||||
MqttConfigMessage(self.format_topic(node, prop), "$name", payload=name),
|
||||
MqttConfigMessage(self.format_topic(node, prop), "$datatype", payload=dtype),
|
||||
MqttConfigMessage(self.format_topic(node, prop), "$settable", payload="true" if settable else "false"),
|
||||
MqttConfigMessage(self.format_topic(node, prop), "$retained", payload="true" if retained else "false")
|
||||
]
|
||||
if unit is not None:
|
||||
retval.append(MqttConfigMessage(self.format_topic(node, prop), "$unit", payload=unit))
|
||||
if dformat is not None:
|
||||
retval.append(MqttConfigMessage(self.format_topic(node, prop), "$format", payload=dformat))
|
||||
return retval
|
||||
|
||||
|
||||
def _setup(self):
|
||||
if not hasattr(self, 'mpc_path'):
|
||||
self.mpc_path = '/usr/bin/mpc'
|
||||
|
||||
|
||||
def config(self):
|
||||
_LOGGER.debug("Configuring")
|
||||
retval = self.mqttHomieDevice("Media Player Daemon (MyRoom)", "controls")
|
||||
retval += self.mqttHomieNode("controls", "Player Controls", "volume,control,play,playlist,current")
|
||||
retval += self.mqttHomieProperty("controls", "volume", "Volume", "integer", True, True, "%", "0:100")
|
||||
retval += self.mqttHomieProperty("controls", "control", "Media Control", "enum", True, True, dformat = "play,pause,stop")
|
||||
retval += self.mqttHomieProperty("controls", "play", "Play Button", "boolean", True, True)
|
||||
retval += self.mqttHomieProperty("controls", "playlist", "Playlist", "string", True, True)
|
||||
retval += self.mqttHomieProperty("controls", "current", "Currently Playing", "string", False, False)
|
||||
return retval
|
||||
|
||||
|
||||
def status_update(self):
|
||||
retval = []
|
||||
try:
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "current"), payload=self.mpc_get_current(), retain=True))
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception in MpdWorker.on_command(): {}".format(e))
|
||||
traceback.print_exc();
|
||||
return retval
|
||||
|
||||
|
||||
def on_command(self, topic, value):
|
||||
retval = []
|
||||
try:
|
||||
value = value.decode('utf-8')
|
||||
_, nodename, propname, operation = topic.split('/')
|
||||
_LOGGER.debug("Command \"%s\", on %s.%s: %s", operation, nodename, propname, value)
|
||||
if propname == "volume" and operation == "set":
|
||||
if self.mpc_set_volume(value):
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "volume"), payload=value, retain=True))
|
||||
elif propname == "control" and operation == "set":
|
||||
if (value == "play" or value == "PLAY") and self.call_mpc(["play"]) == 0:
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "control"), payload=value, retain=True))
|
||||
elif (value == "pause" or value == "PAUSE") and self.call_mpc(["pause"]) == 0:
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "control"), payload=value, retain=True))
|
||||
elif (value == "stop" or value == "STOP") and self.call_mpc(["stop"]) == 0:
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "control"), payload=value, retain=True))
|
||||
elif propname == "play" and operation == "set":
|
||||
if (value == "true" or value == "on") and self.call_mpc(["play"]) == 0:
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "play"), payload="true", retain=True))
|
||||
elif (value == "false" or value == "off") and self.call_mpc(["stop"]) == 0:
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "play"), payload="false", retain=True))
|
||||
elif propname == "playlist" and operation == "set":
|
||||
if self.mpc_set_playlist(value):
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "playlist"), payload=value, retain=True))
|
||||
retval.append(MqttMessage(topic=self.format_topic("controls", "current"), payload=self.mpc_get_current(), retain=True))
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception in MpdWorker.on_command(): {}".format(e))
|
||||
traceback.print_exc();
|
||||
return retval
|
||||
|
||||
|
||||
def run_mpc(self, args):
|
||||
args = [self.mpc_path] + args
|
||||
result = subprocess.run(args, stdout=subprocess.PIPE)
|
||||
_LOGGER.debug("run_mpc: %s -> %s", str(args), str(result))
|
||||
return (result.returncode, result.stdout)
|
||||
|
||||
|
||||
def call_mpc(self, args):
|
||||
args = [self.mpc_path] + args
|
||||
_LOGGER.debug("call_mpc: %s", str(args))
|
||||
return subprocess.call(args)
|
||||
|
||||
|
||||
def mpc_set_volume(self, volume):
|
||||
return self.call_mpc(["volume", str(volume)]) == 0
|
||||
|
||||
|
||||
def mpc_set_playlist(self, pl):
|
||||
return self.call_mpc(["load", str(pl)]) == 0
|
||||
|
||||
|
||||
def mpc_get_current(self):
|
||||
retcode, out = self.run_mpc(["current"])
|
||||
if retcode == 0:
|
||||
return out
|
||||
else:
|
||||
return ""
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
from mqtt import MqttMessage
|
||||
|
||||
from workers.base import BaseWorker
|
||||
import logger
|
||||
import traceback
|
||||
|
||||
REQUIREMENTS = ['pyserial']
|
||||
_LOGGER = logger.get(__name__)
|
||||
|
||||
|
||||
class MsgwWorker(BaseWorker):
|
||||
|
||||
def _setup(self):
|
||||
_LOGGER.debug("Setting up mysensors-mqtt")
|
||||
import serial
|
||||
self.ser = serial.Serial(self.port, self.baudrate, timeout=10)
|
||||
if not hasattr(self, 'encoding'):
|
||||
self.encoding = 'utf-8'
|
||||
|
||||
def config(self):
|
||||
return []
|
||||
|
||||
def run(self, mqtt):
|
||||
_LOGGER.debug("Starting mysensors-mqtt at: %s" % self.ser.name)
|
||||
while True:
|
||||
try:
|
||||
line = self.ser.readline()
|
||||
if not line:
|
||||
continue
|
||||
splited_line = self.format_topic(line.decode(self.encoding).strip()).split(';')
|
||||
_LOGGER.debug("MSGW.serial.read: %s" % line)
|
||||
topic = '/'.join(splited_line[0:-1])
|
||||
payload = ''.join(splited_line[-1])
|
||||
mqtt.publish([MqttMessage(topic=topic, payload=payload)])
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception in MsgwWorker.run(): {}".format(e))
|
||||
traceback.print_exc();
|
||||
except serial.serialutil.SerialException as e:
|
||||
_LOGGER.error("Caught exception in MsgwWorker.run(): {}".format(e))
|
||||
traceback.print_exc();
|
||||
self.ser = serial.Serial(self.port, self.baudrate, timeout=10)
|
||||
|
||||
|
||||
def on_command(self, topic, value):
|
||||
_LOGGER.debug("MsgwWorker.on_command({}, {})".format(topic, value))
|
||||
try:
|
||||
splited_topic = topic.split('/')
|
||||
line = str.encode(splited_topic[-5]+";"+splited_topic[-4]+";"+splited_topic[-3]+";"+splited_topic[-2]+";"+splited_topic[-1]+";")+value+b'\n'
|
||||
_LOGGER.debug("MSGW.serial.write: %s" % line)
|
||||
self.ser.write(line)
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception in MsgwWorker.on_command(): {}".format(e))
|
||||
traceback.print_exc()
|
||||
return []
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
from mqtt import MqttMessage
|
||||
|
||||
from workers.base import BaseWorker
|
||||
import logger
|
||||
import traceback
|
||||
|
||||
REQUIREMENTS = ['pyserial']
|
||||
_LOGGER = logger.get(__name__)
|
||||
|
||||
|
||||
class Msgw2Worker(BaseWorker):
|
||||
|
||||
def _setup(self):
|
||||
_LOGGER.debug("Setting up mysensors-2-mqtt")
|
||||
import serial
|
||||
self.ser = serial.Serial(self.port, self.baudrate, timeout=10)
|
||||
if not hasattr(self, 'encoding'):
|
||||
self.encoding = 'utf-8'
|
||||
|
||||
def config(self):
|
||||
return []
|
||||
|
||||
def run(self, mqtt):
|
||||
_LOGGER.debug("Starting mysensors-2-mqtt at: %s" % self.ser.name)
|
||||
while True:
|
||||
try:
|
||||
line = self.ser.readline()
|
||||
if not line:
|
||||
continue
|
||||
splited_line = self.format_topic(line.decode(self.encoding).strip()).split(';')
|
||||
_LOGGER.debug("MSGW2.serial.read: %s" % line)
|
||||
topic = '/'.join(splited_line[0:-1])
|
||||
payload = ''.join(splited_line[-1])
|
||||
mqtt.publish([MqttMessage(topic=topic, payload=payload)])
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception in Msgw2Worker.run(): {}".format(e))
|
||||
traceback.print_exc();
|
||||
except serial.serialutil.SerialException as e:
|
||||
_LOGGER.error("Caught exception in MsgwWorker.run(): {}".format(e))
|
||||
traceback.print_exc();
|
||||
self.ser = serial.Serial(self.port, self.baudrate, timeout=10)
|
||||
|
||||
|
||||
def on_command(self, topic, value):
|
||||
_LOGGER.debug("MsgwWorker2.on_command({}, {})".format(topic, value))
|
||||
try:
|
||||
splited_topic = topic.split('/')
|
||||
line = str.encode(splited_topic[-5]+";"+splited_topic[-4]+";"+splited_topic[-3]+";"+splited_topic[-2]+";"+splited_topic[-1]+";")+value+b'\n'
|
||||
_LOGGER.info("MSGW2.serial.write: %s" % line)
|
||||
self.ser.write(line)
|
||||
except Exception as e:
|
||||
_LOGGER.error("Caught exception in Msgw2Worker.on_command(): {}".format(e))
|
||||
traceback.print_exc()
|
||||
return []
|
||||
|
||||
+10
-6
@@ -83,10 +83,14 @@ class WorkersManager:
|
||||
raise "%s cannot be initialized, it has to define run or status_update method" % worker_name
|
||||
|
||||
if 'topic_subscription' in worker_config:
|
||||
self._mqtt_callbacks.append((
|
||||
worker_config['topic_subscription'],
|
||||
partial(self._on_command_wrapper, worker_obj)
|
||||
))
|
||||
topics = worker_config['topic_subscription']
|
||||
if isinstance(topics, str):
|
||||
topics = [topics]
|
||||
for topic in topics:
|
||||
self._mqtt_callbacks.append((
|
||||
topic,
|
||||
partial(self._on_command_wrapper, worker_obj)
|
||||
))
|
||||
|
||||
if 'topic_subscription' in self._config:
|
||||
for (callback_name, options) in self._config['topic_subscription'].items():
|
||||
@@ -148,6 +152,6 @@ class WorkersManager:
|
||||
for command in self._config_commands:
|
||||
messages = command.execute()
|
||||
for msg in messages:
|
||||
msg.topic = "{}/{}".format(self._config['sensor_config'].get('topic', 'homeassistant'), msg.topic)
|
||||
#msg.topic = "{}/{}".format(self._config['sensor_config'].get('topic', 'homeassistant'), msg.topic)
|
||||
msg.retain = self._config['sensor_config'].get('retain', True)
|
||||
mqtt.publish(messages)
|
||||
mqtt.publish(messages)
|
||||
|
||||
Reference in New Issue
Block a user