def discover(bridge_config, new_lights): logging.debug("tasmota: <discover> invoked!") device_ips = check_output("nmap " + getIpAddress() + "/24 -p80 --open -n | grep report | cut -d ' ' -f5", shell=True).decode('utf-8').rstrip("\n").split("\n") del device_ips[-1] #delete last empty element in list for ip in device_ips: try: logging.debug ( "tasmota: probing ip " + ip) response = requests.get ("http://" + ip + "/cm?cmnd=Status%200", timeout=3) if response.status_code == 200: device_data = json.loads(response.text) #logging.debug(pretty_json(device_data)) if ("StatusSTS" in device_data) and ("Color" in device_data["StatusSTS"]): logging.debug("tasmota: " + ip + " is a Tasmota device ") logging.debug ("tasmota: Hostname: " + device_data["StatusNET"]["Hostname"] ) logging.debug ("tasmota: Mac: " + device_data["StatusNET"]["Mac"] ) properties = {"rgb": True, "ct": False, "ip": ip, "name": device_data["StatusNET"]["Hostname"], "id": device_data["StatusNET"]["Mac"], "mac": device_data["StatusNET"]["Mac"]} device_exist = False for light in bridge_config["lights_address"].keys(): if bridge_config["lights_address"][light]["protocol"] == "tasmota" and bridge_config["lights_address"][light]["id"] == properties["id"]: device_exist = True bridge_config["lights_address"][light]["ip"] = properties["ip"] logging.debug("tasmota: light id " + properties["id"] + " already exist, updating ip...") break if (not device_exist): light_name = "Tasmota id " + properties["id"][-8:] if properties["name"] == "" else properties["name"] logging.debug("tasmota: Add Tasmota: " + properties["id"]) modelid = "Tasmota" new_light_id = nextFreeId(bridge_config, "lights") bridge_config["lights"][new_light_id] = {"state": light_types[modelid]["state"], "type": light_types[modelid]["type"], "name": light_name, "uniqueid": "4a:e0:ad:7f:cf:" + str(random.randrange(0, 99)) + "-1", "modelid": modelid, "manufacturername": "Tasmota", "swversion": light_types[modelid]["swversion"]} new_lights.update({new_light_id: {"name": light_name}}) bridge_config["lights_address"][new_light_id] = {"ip": properties["ip"], "id": properties["id"], "protocol": "tasmota"} except Exception as e: logging.debug("tasmota: ip " + ip + " is unknow device, " + str(e))
def discover(bridge_config, new_lights): logging.debug("ESPHome: <discover> invoked!") device_ips = check_output( "nmap " + getIpAddress() + "/24 -p80 --open -n | grep report | cut -d ' ' -f5", shell=True).decode('utf-8').rstrip("\n").split("\n") del device_ips[-1] # delete last empty element in list for ip in device_ips: try: logging.debug("ESPHome: probing ip " + ip) response = requests.get("http://" + ip + "/text_sensor/light_id", timeout=3) device = json.loads(response.text)['state'].split( ';') # get device data mac = device[1] device_name = device[2] ct_boost = device[3] rgb_boost = device[4] if response.status_code == 200 and device[ 0] == "esphome_diyhue_light": logging.debug("ESPHome: Found " + device_name + " at ip " + ip) white_response = requests.get("http://" + ip + "/light/white_led", timeout=3) color_response = requests.get("http://" + ip + "/light/color_led", timeout=3) dim_response = requests.get("http://" + ip + "/light/dimmable_led", timeout=3) toggle_response = requests.get("http://" + ip + "/light/toggle_led", timeout=3) if (white_response.status_code != 200 and color_response.status_code != 200 and dim_response != 200 and toggle_response != 200): logging.debug( "ESPHome: Device has improper configuration! Exiting.") raise elif (white_response.status_code == 200 and color_response.status_code == 200): logging.debug("ESPHome: " + device_name + " is a RGBW ESPHome device") white_device_data = json.loads(white_response.text) color_device_data = json.loads(color_response.text) properties = { "rgb": True, "ct": True, "ip": ip, "name": device_name, "id": mac, "mac": mac, "ct_boost": ct_boost, "rgb_boost": rgb_boost } esphome_model = "ESPHome-RGBW" modelid = "LCT015" elif (white_response.status_code == 200): logging.debug("ESPHome: " + device_name + " is a CT ESPHome device") white_device_data = json.loads(white_response.text) properties = { "rgb": False, "ct": True, "ip": ip, "name": device_name, "id": mac, "mac": mac, "ct_boost": ct_boost, "rgb_boost": rgb_boost } esphome_model = "ESPHome-CT" modelid = "LWB010" elif (color_response.status_code == 200): logging.debug("ESPHome: " + device_name + " is a RGB ESPHome device") color_device_data = json.loads(color_response.text) properties = { "rgb": True, "ct": False, "ip": ip, "name": device_name, "id": mac, "mac": mac, "ct_boost": ct_boost, "rgb_boost": rgb_boost } esphome_model = "ESPHome-RGB" modelid = "ESPHome-RGB" elif (dim_response.status_code == 200): logging.debug("ESPHome: " + device_name + " is a Dimmable ESPHome device") dim_device_data = json.loads(dim_response.text) properties = { "rgb": False, "ct": False, "ip": ip, "name": device_name, "id": mac, "mac": mac, "ct_boost": ct_boost, "rgb_boost": rgb_boost } esphome_model = "ESPHome-Dimmable" modelid = "ESPHome-Dimmable" elif (toggle_response.status_code == 200): logging.debug("ESPHome: " + device_name + " is a Toggle ESPHome device") toggle_device_data = json.loads(toggle_response.text) properties = { "rgb": False, "ct": False, "ip": ip, "name": device_name, "id": mac, "mac": mac, "ct_boost": ct_boost, "rgb_boost": rgb_boost } esphome_model = "ESPHome-Toggle" modelid = "ESPHome-Toggle" device_exist = False for light in bridge_config["lights_address"].keys(): if bridge_config["lights_address"][light][ "protocol"] == "esphome" and bridge_config[ "lights_address"][light]["id"] == properties[ "id"]: device_exist = True bridge_config["lights_address"][light][ "ip"] = properties["ip"] bridge_config["lights_address"][light][ "ct_boost"] = properties["ct_boost"] bridge_config["lights_address"][light][ "rgb_boost"] = properties["rgb_boost"] logging.debug( "ESPHome: light id " + properties["id"] + " already exists, updating device data...") break if (not device_exist): light_name = "ESPHome id " + \ properties["id"][-8:] if properties["name"] == "" else properties["name"] logging.debug("ESPHome: Adding ESPHome " + properties["id"]) new_light_id = nextFreeId(bridge_config, "lights") bridge_config["lights"][new_light_id] = {} bridge_config["lights"][new_light_id][ "state"] = light_types[modelid]["state"] bridge_config["lights"][new_light_id][ "type"] = light_types[modelid]["type"] bridge_config["lights"][new_light_id]["name"] = light_name bridge_config["lights"][new_light_id]["modelid"] = modelid bridge_config["lights"][new_light_id][ "manufacturername"] = light_types[modelid][ "manufacturername"] bridge_config["lights"][new_light_id][ "swversion"] = light_types[modelid]["swversion"] bridge_config["lights"][new_light_id][ "config"] = light_types[modelid]["config"] bridge_config["lights"][new_light_id]["uniqueid"] = mac if modelid == "LCT015": bridge_config["lights"][new_light_id][ "capabilities"] = light_types[modelid][ "capabilities"] bridge_config["lights"][new_light_id][ "streaming"] = light_types[modelid]["streaming"] #new_lights.update({new_light_id: {"name": light_name}}) bridge_config["lights_address"][new_light_id] = {} bridge_config["lights_address"][new_light_id][ "ip"] = properties["ip"] bridge_config["lights_address"][new_light_id][ "id"] = properties["id"] bridge_config["lights_address"][new_light_id][ "protocol"] = "esphome" bridge_config["lights_address"][new_light_id][ "rgb_boost"] = rgb_boost bridge_config["lights_address"][new_light_id][ "ct_boost"] = ct_boost bridge_config["lights_address"][new_light_id][ "esphome_model"] = esphome_model except Exception as e: logging.debug("ESPHome: ip " + ip + " is unknown device, " + str(e))
def discover(bridge_config, new_lights): logging.debug("shelly: <discover> invoked!") device_ips = check_output( "nmap " + getIpAddress() + "/24 -p80 --open -n | grep report | cut -d ' ' -f5", shell=True).decode('utf-8').rstrip("\n").split("\n") del device_ips[-1] # delete last empty element in list for ip in device_ips: logging.debug("shelly: found ip: " + ip) try: logging.debug("shelly: probing ip " + ip) response = requests.get("http://" + ip + "/shelly", timeout=5) if response.status_code == 200: device_data = json.loads(response.text) if device_data["type"] == "SHSW-1": logging.debug("shelly: " + ip + " is a shelly device ") shelly_response = requests.get("http://" + ip + "/status", timeout=5) shelly_data = json.loads(shelly_response.text) logging.debug("shelly: ip: " + shelly_data["wifi_sta"]["ip"]) logging.debug("shelly: Mac: " + shelly_data["mac"]) properties = { "ip": ip, "name": ip, "id": shelly_data["mac"], "mac": shelly_data["mac"] } device_exist = False for light in bridge_config["lights_address"].keys(): if bridge_config["lights_address"][light]["protocol"] == "shelly" and \ bridge_config["lights_address"][light]["id"] == properties["id"]: device_exist = True bridge_config["lights_address"][light][ "ip"] = properties["ip"] logging.debug("shelly: light id " + properties["id"] + " already exist, updating ip...") break if (not device_exist): light_name = "shelly id " + properties["id"][ -8:] if properties["name"] == "" else properties[ "name"] logging.debug("shelly: Add shelly: " + properties["id"]) modelid = "Shelly" new_light_id = nextFreeId(bridge_config, "lights") bridge_config["lights"][new_light_id] = { "state": light_types[modelid]["state"], "type": light_types[modelid]["type"], "name": light_name, "uniqueid": "4a:e0:ad:7f:cf:" + str(random.randrange(0, 99)) + "-1", "modelid": modelid, "manufacturername": "Shelly", "swversion": light_types[modelid]["swversion"] } new_lights.update({new_light_id: {"name": light_name}}) bridge_config["lights_address"][new_light_id] = { "ip": properties["ip"], "id": properties["id"], "protocol": "shelly" } except Exception as e: logging.debug("shelly: ip " + ip + " is unknow device, " + str(e))
def parse_arguments(): argumentDict = { "BIND_IP": '', "HOST_IP": '', "HTTP_PORT": '', "HTTPS_PORT": '', "FULLMAC": '', "MAC": '', "DEBUG": False, "DOCKER": False, "IP_RANGE_START": '', "IP_RANGE_END": '', "DECONZ": '', "scanOnHostIP": False, "disableOnlineDiscover": '', "noLinkButton": False, "noServeHttps": False } ap = argparse.ArgumentParser() # Arguements can also be passed as Environment Variables. ap.add_argument("--debug", action='store_true', help="Enables debug output") ap.add_argument("--bind-ip", help="The IP address to listen on", type=str) ap.add_argument("--config_path", help="Set certificate and config files location", type=str) ap.add_argument("--docker", action='store_true', help="Enables setup for use in docker container") ap.add_argument("--ip", help="The IP address of the host system (Docker)", type=str) ap.add_argument("--http-port", help="The port to listen on for HTTP (Docker)", type=int) ap.add_argument("--https-port", help="The port to listen on for HTTPS (Docker)", type=int) ap.add_argument("--mac", help="The MAC address of the host system (Docker)", type=str) ap.add_argument("--no-serve-https", action='store_true', help="Don't listen on port 443 with SSL") ap.add_argument( "--ip-range", help="Set IP range for light discovery. Format: <START_IP>,<STOP_IP>", type=str) ap.add_argument( "--scan-on-host-ip", action='store_true', help="Scan the local IP address when discovering new lights") ap.add_argument( "--deconz", help= "Provide the IP address of your Deconz host. 127.0.0.1 by default.", type=str) ap.add_argument( "--no-link-button", action='store_true', help= "DANGEROUS! Don't require the link button to be pressed to pair the Hue app, just allow any app to connect" ) ap.add_argument("--disable-online-discover", help="Disable Online and Remote API functions") args = ap.parse_args() if args.scan_on_host_ip: argumentDict["scanOnHostIP"] = True if args.no_link_button: argumentDict["noLinkButton"] = True if args.no_serve_https: argumentDict["noServeHttps"] = True if args.debug or get_environment_variable('DEBUG', True): argumentDict["DEBUG"] = True config_path = '/opt/hue-emulator/config' if args.config_path: config_path = args.config_path elif get_environment_variable('CONFIG_PATH'): config_path = get_environment_variable('CONFIG_PATH') argumentDict["CONFIG_PATH"] = config_path bind_ip = '0.0.0.0' if args.bind_ip: bind_ip = args.bind_ip elif get_environment_variable('BIND_IP'): bind_ip = get_environment_variable('BIND_IP') argumentDict["BIND_IP"] = bind_ip if args.ip: host_ip = args.ip elif get_environment_variable('IP'): host_ip = get_environment_variable('IP') elif bind_ip != '0.0.0.0': host_ip = bind_ip else: host_ip = getIpAddress() argumentDict["HOST_IP"] = host_ip if args.http_port: host_http_port = args.http_port elif get_environment_variable('HTTP_PORT'): host_http_port = int(get_environment_variable('HTTP_PORT')) else: host_http_port = 80 argumentDict["HTTP_PORT"] = host_http_port if args.https_port: host_https_port = args.https_port elif get_environment_variable('HTTPS_PORT'): host_https_port = int(get_environment_variable('HTTPS_PORT')) else: host_https_port = 443 argumentDict["HTTPS_PORT"] = host_https_port logging.info("Using Host %s:%s" % (host_ip, host_http_port)) if args.mac: dockerMAC = args.mac # keeps : for cert generation mac = str(args.mac).replace(":", "") elif get_environment_variable('MAC'): dockerMAC = get_environment_variable('MAC').strip('\u200e') mac = str(dockerMAC).replace(":", "") else: dockerMAC = check_output( "cat /sys/class/net/$(ip -o addr | grep %s | awk '{print $2}')/address" % host_ip, shell=True).decode('utf-8')[:-1] mac = str(dockerMAC).replace(":", "") if args.docker or get_environment_variable('DOCKER', True): docker = True else: docker = False argumentDict["FULLMAC"] = dockerMAC argumentDict["MAC"] = mac argumentDict["DOCKER"] = docker logging.info("Host MAC given as " + mac) if args.ip_range or get_environment_variable('IP_RANGE'): if args.ip_range: ranges = args.ip_range else: ranges = get_environment_variable('IP_RANGE') ranges = ranges.split(',') if ranges[0] and int(ranges[0]) >= 0: ip_range_start = int(ranges[0]) else: ip_range_start = 0 if ranges[1] and int(ranges[1]) > 0: ip_range_end = int(ranges[1]) else: ip_range_end = 255 elif get_environment_variable( 'IP_RANGE_START') and get_environment_variable('IP_RANGE_END'): ip_range_start = get_environment_variable('IP_RANGE_START') ip_range_end = get_environment_variable('IP_RANGE_END') else: ip_range_start = 0 ip_range_end = 255 argumentDict["IP_RANGE_START"] = ip_range_start argumentDict["IP_RANGE_END"] = ip_range_end logging.info("IP range for light discovery: " + str(ip_range_start) + "-" + str(ip_range_end)) if args.deconz: deconz_ip = args.deconz elif get_environment_variable('DECONZ'): deconz_ip = get_environment_variable('DECONZ') else: deconz_ip = "127.0.0.1" argumentDict["DECONZ"] = deconz_ip logging.info("Deconz IP given as " + deconz_ip) if args.disable_online_discover or get_environment_variable( 'disableonlinediscover'): disableOnlineDiscover = True logging.info("Online Discovery/Remote API Disabled!") else: disableOnlineDiscover = False logging.info("Online Discovery/Remote API Enabled!") argumentDict["disableOnlineDiscover"] = disableOnlineDiscover if argumentDict['noServeHttps']: logging.info("HTTPS Port Disabled") return argumentDict