I have written some complicated DSL code full of nested lambdas, it was a pain.
Now with fresh and weak knowledge of Python:
I managed to port all my old DSL, which more or less a one to one porting.
But now I created a new project:
Support of Hue Groups (As this is not supported by the binding)
Here how it works:
You define an Item representing the group item in OH:
Dimmer TreppeGang "Treppe und Gang Licht [%d %%]" {hue="group.rule" [group_name="Treppe Gang Gruppe"]}
Metadata has to contain the hue group name, here it is “Treppe Gang Gruppe”, which has to be defined by an external tool.
And here the rule to manage the groups(s):
from core.triggers import ItemStateUpdateTrigger, CronTrigger #, ItemStateUpdateTrigger
from core.jsr223.scope import events
from core.log import logging, LOG_PREFIX
from core.rules import rule
import requests
import yaml, json
from time import sleep
from core import osgi
metadata_registry = osgi.get_service(
"org.openhab.core.items.MetadataRegistry"
) or osgi.get_service(
"org.eclipse.smarthome.core.items.MetadataRegistry"
)
HUE_BRIDGE = "vevedock-09" # add ip address or name of gateway
API_CODE = "72B99A4ECE" # API-Token
POLL_INTERVAL = 15 # poll interval for getting values set outside of openhab
log = logging.getLogger(LOG_PREFIX + ".huegroups.log")
class HueGroup(object):
def __init__(self, group_id, group_data, meta_hash):
self.group_id = group_id
self.group_data = group_data
self.meta_hash = meta_hash
self.stored_bri = 0
def setVal(self, value):
if str(value) != "0":
self.stored_bri = round(value.floatValue()*255/100)
self.setValHTTP(True, self.stored_bri)
else:
if self.stored_bri > 1:
self.setValHTTP(False, 1)
sleep(0.1)
self.setValHTTP(False, None)
def setValHTTP(self, on, bri):
post_data = {}
if on != None:
post_data["on"] = on
if bri != None:
post_data["bri"] = bri
if len(post_data) > 0:
r =requests.put('http://{}/api/{}/groups/{}/action'.format(HUE_BRIDGE, API_CODE, self.group_id), json.dumps(post_data))
def getVal(self):
self.getValHTTP()
def getValHTTP(self):
r =requests.get('http://{}/api/{}/groups/{}/'.format(HUE_BRIDGE, API_CODE, self.group_id))
response = yaml.load(r.content)
got_bri = round(response["action"]["bri"]*100/255)
if response["action"]["on"]:
if abs(self.stored_bri - got_bri) > 1 :
self.stored_bri = got_bri
events.postUpdate(self.meta_hash[self.group_data["name"]], str(got_bri))
else:
events.postUpdate(self.meta_hash[self.group_data["name"]], "0")
self.stored_bri = 0
class HueGroupMgr(object):
def __init__(self):
self.meta_hash = self.getMetaData()
self.all_group_data = self.loadGroups()
self.group_items = { itm: HueGroup(itm, self.all_group_data[itm], self.meta_hash) for itm in self.all_group_data }
def loadGroups(self):
r =requests.get('http://{}/api/{}/groups'.format(HUE_BRIDGE, API_CODE))
if r.status_code == 200:
return { group : attributes for (group, attributes) in yaml.load(r.content).items() if attributes['name'] in self.meta_hash}
else:
return {}
def getMetaData(self):
meta_data = metadata_registry.getAll()
return { meta.getConfiguration()["group_name"] : str(meta.getUID()).split(":")[1] for meta in meta_data.toArray() if meta.getValue() == "group.rule"}
def getAllTriggers(self):
all_trig = []
for item in self.all_group_data:
all_trig.append(ItemStateUpdateTrigger(self.meta_hash[self.all_group_data[item]["name"]], None, str(item)).trigger)
if len(all_trig) > 0:
all_trig.append(CronTrigger("0/{} * * * * ?".format(POLL_INTERVAL), "POLL").trigger,)
# all_trig.append(ItemStateUpdateTrigger("proxySW", None, "POLL").trigger)
return all_trig
def execute(self, module, inputs):
cmd = str(inputs["module"]).split("_")[0] if len(inputs) > 0 else "POLL"
if cmd == "POLL":
for group_id in self.group_items:
self.group_items[group_id].getVal()
else:
self.group_items[cmd].setVal(inputs["state"])
hueGroupMgr = HueGroupMgr()
@rule("Hue Group Manager Rule", description="This is an rule for adding groups support for hue groups")
class HueGroupsRule(object):
def __init__(self):
self.triggers = hueGroupMgr.getAllTriggers()
def execute(self, module, inputs):
hueGroupMgr.execute(module, inputs)
The work with Visual Studio Code and Jython is amazing.
The code is far away from perfect, feedback what could be done better is appreciated.
The next thing I will add are scenes.
A big “Thanks” to all who have contributed to JSR223 and Jython for the current state.