#!/usr/bin/env python3 import _thread import time from datetime import datetime import paho.mqtt.client as mqt import smbus bus = smbus.SMBus(1) mqtc = mqt.Client() access = {} # [ code : [last_access, penalty] ] bus_use = True def allowed(code): print(access) if code in access: if millis_since(access[code][0]) > 3000 + access[code][1]: access[code] = [datetime.now(), 0] return True else: access[code] = [datetime.now(), access[code][1] + 3000] return False else: access[code] = [datetime.now(), 0] return True def millis_since(start_time): dt = datetime.now() - start_time ms = (dt.days * 24 * 60 * 60 + dt.seconds) * 1000 + dt.microseconds / 1000.0 return ms def on_connect(mosq, obj, foo, bar): print("Connected") def on_message(mosq, obj, msg): # print( "Received on topic: " + msg.topic + " Message: "+str(msg.payload) ); msgs(msg.payload, msg.topic) def on_subscribe(mosq, obj, mid, granted_qos): print("Subscribed OK") # Funktion Setze Bit in Variable / Function Set Bit in byte def set_bit(value, bit): return value | (1 << bit) # Funktion rücksetzte Bit in Variable / Function reset Bit in byte def clear_bit(value, bit): return value & ~(1 << bit) def eval_time_diff(switch, start, end): print("Switch: " + str(switch) + " was pressed for " + str(end - start) + "MS") d = end - start if d < 600 and switch == 7: zentral_aus() print("Zentral Aus gedrueckt") return if d < 600: # Single Switch state[switch] ^= 1 send_state() def i2c_status_thread_new(): global bus_use, state state_timer = [0, 0, 0, 0, 0, 0, 0, 0] while True: while bus_use: for pos, i2c_input in enumerate(inputs): byte = bus.read_byte(i2c_input) for c, i in i2c_inputs[pos].items(): ns = 1 if byte | c == c else 0 # get new state # if i == 7: # zentral_aus() # print( "zentral-aus" ) # continue if state[i] != ns and not i in [1, 2, 3, 6]: # Turned on mqtc.publish("foobar/oben/" + names[i][0] + "/" + services[names[i][1]] + "/status", states[ns], qos=0, retain=False) state[i] = ns if i in (1, 2, 3, 6, 7): if ns == 0 and state_timer[i] > 0: eval_time_diff(i, state_timer[i], int(time.time() * 1000)) state_timer[i] = 0 if ns == 1 and state_timer[i] == 0: state_timer[i] = int(time.time() * 1000) time.sleep(0.1) # abtastrate für die schalter time.sleep(1) # Buttonbefehle def switch(i, speed=0.5): global bus_use # if allowed(i): bus_use = False print("Switched: " + str(i) + " Speed: " + str(speed)) o = 0 if 7 < i < 16: o = set_bit(o, i - 8) bus.write_byte(0x3f, 255 - o) time.sleep(speed) o = clear_bit(o, i - 8) bus.write_byte(0x3f, 255 - o) elif i < 8: o = set_bit(o, i) bus.write_byte(0x21, 255 - o) time.sleep(speed) o = clear_bit(o, i) bus.write_byte(0x21, 255 - o) bus_use = True def strobo_switch(switch_list, speed=0.5): global bus_use bus_use = False for i in switch_list: o = 0 if i > 7: o = set_bit(o, i - 8) bus.write_byte(0x3f, 255 - o) time.sleep(speed) o = clear_bit(o, i - 8) bus.write_byte(0x3f, 255 - o) else: o = set_bit(o, i) bus.write_byte(0x21, 255 - o) time.sleep(speed) o = clear_bit(o, i) bus.write_byte(0x21, 255 - o) bus_use = True services = ["strom", "licht"] state = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] inputs = (0x23, 0x3a) states = {0: "off", 1: "on"} commands = {"flur": 0, "baellebad": 1, "lounge-front": 2, "lounge-back": 3, "baellebad-ein": 4, "lounge-ein": 5, "cantina-ein": 6, "zentral-aus": 7, "cantina": 8} i2c_inputs = [{0xFE: 4, 0xFD: 5, 0xFB: 8, 0xF7: 0, 0xEF: 2, 0xDF: 1, 0xBF: 3, 0x7F: 6}, {0xFE: 7}] names = {7: ["zentral", 0], 4: ["baellebad", 0], 5: ["lounge", 0], 6: ["cantina", 0], 0: ["flur", 1], 1: ["baellebad", 1], 2: ["lounge-front", 1], 3: ["lounge-back", 1], 8: ["cantina", 1]} power = {"zentral": 7, "baellebad": 4, "lounge": 5, "cantina": 6} light = {"flur": 0, "baellebad": 1, "lounge-front": 2, "lounge-back": 3, "cantina": 8} # foobar/oben/lounge /licht/action # cantina /strom/status # flur # baellebad # zentral def zentral_aus(): for i in range(len(state)): state[i] = 0 send_state() # for k,v in names.items(): # mqtc.publish("foobar/oben/" + v[0] + "/" + services[v[1]] + "/status", "off" ) def switch_state(i, state_, speed=0.5): if state[i] != state_: # changed switch(i, speed=0.5) state[i] = state_ return state[i] def switch_toggle(i, speed=0.5): switch(i, speed=speed) # power can only be switched on, and centrally shutdown # if i in [ 4,5,6]: # state[i] = 1 # not anymore if i == 7: state[i] = 0 elif i < 16: state[i] = 0 if state[i] == 1 else 1 mqtc.publish("foobar/oben/" + names[i][0] + "/" + services[names[i][1]] + "/status", states[state[i]]) def decode_topic(topic, state): clist = topic.split('/') if clist[3] == "strom" and clist[2] == "zentral": zentral_aus() if clist[3] == "licht" and clist[2] in light: ns = switch_state(light[clist[2]], state) mqtc.publish(topic.replace("action", "status"), states[ns], qos=0, retain=False) if clist[3] == "strom" and clist[2] in power: ns = switch_state(power[clist[2]], state) mqtc.publish(topic.replace("action", "status"), states[ns], qos=0, retain=False) def msgs(inp, topic): c = inp.decode("utf-8") l = len(c) # supporting number commands if c == "on" or c == "off": if c.find("on") >= 0: decode_topic(topic, 1) elif c.find("off") >= 0: decode_topic(topic, 0) return elif l < 3: try: msg = int(inp) switch_toggle(msg) except ValueError: return # supporting string commands with dimming parameters else: cmds = c.split(",") if len(cmds) > 1: command = 9001 # error checking if cmds[0] in commands: command = commands[cmds[0]] else: return try: arg = int(cmds[1]) except ValueError: return # strobo if (command == 100 or command == 99) and arg < 100: for i in range(arg): switch((100 - command) * 8, speed=0.05) time.sleep(0.06) elif command == 101 and arg < 100: for i in range(arg): strobo_switch([0, 8], speed=0.05) time.sleep(0.01) # command with parameter used for dimming else: if arg < 100: switch(command, speed=4 * arg / 100 + 1) if state[command] == 0: state[command] = 1 mqtc.publish("foobar/oben/" + names[command][0] + "/" + services[names[command][1]] + "/status", states[state[command]]) # single string command without parameter else: print("One Command") if commands[c] == 7: zentral_aus() if c in commands: switch_toggle(commands[c]) return def send_state(): for i in range(len(state)): try: mqtc.publish("foobar/oben/" + names[i][0] + "/" + services[names[i][1]] + "/status", states[state[i]]) except KeyError: pass def init_mqtt(): mqtc.connect("mqtt.chaospott.de", 1883, 60) mqtc.subscribe("foobar/oben/licht", 0) mqtc.subscribe("foobar/oben/lounge-back/licht/action", 0) mqtc.subscribe("foobar/oben/lounge-front/licht/action", 0) mqtc.subscribe("foobar/oben/lounge/strom/action", 0) mqtc.subscribe("foobar/oben/baellebad/licht/action", 0) mqtc.subscribe("foobar/oben/baellebad/strom/action", 0) mqtc.subscribe("foobar/oben/cantina/licht/action", 0) mqtc.subscribe("foobar/oben/cantina/strom/action", 0) mqtc.subscribe("foobar/oben/flur/licht/action", 0) mqtc.subscribe("foobar/oben/strom/zentral/licht/action", 0) mqtc.on_message = on_message mqtc.on_connect = on_connect mqtc.on_subscribe = on_subscribe _thread.start_new_thread(i2c_status_thread_new, ()) mqtc.loop_start() while True: # try: # print("Err") # mqtc.loop_forever() # except: # pass time.sleep(60) send_state() init_mqtt() # vim: noai:ts=4:sw=4