Skip to content

Commit

Permalink
undo fix for special characters
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusmotea authored Feb 26, 2019
1 parent bf08d62 commit 07bed23
Showing 1 changed file with 44 additions and 29 deletions.
73 changes: 44 additions & 29 deletions BridgeEmulator/HueEmulator3.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

ap = argparse.ArgumentParser()

# Arguements can also be passed as Environment Variables.
ap.add_argument("--ip", help="The IP address of the host system", nargs='?', const=None, type=str)
ap.add_argument("--mac", help="The MAC address of the host system", nargs='?', const=None, type=str)
ap.add_argument("--debug", help="Enables debug output", nargs='?', const=None, type=str)
Expand All @@ -41,7 +42,7 @@

args = ap.parse_args()

if args.debug and (args.debug == "true" or args.debug == "True"):
if (args.debug and (args.debug == "true" or args.debug == "True")) or (os.getenv('DEBUG') and (os.getenv('DEBUG') == "true" or os.getenv('DEBUG') == "True")):
print("Debug Enabled")
root = logging.getLogger()
root.setLevel(logging.INFO)
Expand All @@ -55,23 +56,31 @@
HostIP = args.ip
print("Host IP given as " + HostIP)
else:
HostIP = getIpAddress()
HostIP = os.getenv('IP_ADDRESS', getIpAddress())
print("Using Host IP of " + HostIP)

if args.mac:
dockerMAC = args.mac
mac = str(args.mac).replace(":","")
print("Host MAC given as " + mac)
elif os.getenv('MAC_ADDRESS'):
dockerMAC = os.getenv('MAC_ADDRESS')
mac = str(dockerMAC).replace(":","")
print("Host MAC given as " + mac)
else:
dockerMAC = check_output("cat /sys/class/net/$(ip -o addr | grep " + HostIP + " | awk '{print $2}')/address", shell=True).decode('utf-8')[:-1]
mac = check_output("cat /sys/class/net/$(ip -o addr | grep " + HostIP + " | awk '{print $2}')/address", shell=True).decode('utf-8').replace(":","")[:-1]
logging.info(mac)

if args.docker:
if args.docker or (os.getenv('DOCKER') and os.getenv('DOCKER') == "true"):
print("Docker Setup Initiated")
docker = True
dockerSetup(dockerMAC)
print("Docker Setup Complete")

elif os.getenv('MAC_ADDRESS'):
dockerMAC = os.getenv('MAC_ADDRESS')
mac = str(dockerMAC).replace(":","")
print("Host MAC given as " + mac)
else:
docker = False

Expand All @@ -87,8 +96,8 @@
else:
ip_range_end = 255
else:
ip_range_start = 0
ip_range_end = 255
ip_range_start = os.getenv('IP_RANGE_START', 0)
ip_range_end = os.getenv('IP_RANGE_END', 255)
logging.info("IP range for light discovery: "+str(ip_range_start)+"-"+str(ip_range_end))

protocols = [yeelight, tasmota, native_single, native_multi]
Expand Down Expand Up @@ -147,7 +156,7 @@ def updateConfig():
bridge_config["lights"][light]["config"].update({"startup": {"mode": "safety","configured": False}})
#set entertainment streaming to inactive on start/restart
for group in bridge_config["groups"].keys():
if bridge_config["groups"][group]["type"] == "Entertainment":
if "type" in bridge_config["groups"][group] and bridge_config["groups"][group]["type"] == "Entertainment":
bridge_config["groups"][group]["stream"].update({"active": False, "owner": None})
#fix timezones bug
if "values" not in bridge_config["capabilities"]["timezones"]:
Expand Down Expand Up @@ -212,7 +221,7 @@ def addHueSwitch(uniqueid, sensorsType):

#load config files
try:
with open(cwd +'/config.json', 'r') as fp:
with open(cwd +'/config.json', 'r', encoding="utf-8") as fp:
bridge_config = json.load(fp)
logging.info("Config loaded")
except Exception:
Expand Down Expand Up @@ -249,7 +258,7 @@ def loadConfig(): #load and configure alarm virtual light
loadConfig()

def saveConfig(filename='config.json'):
with open(cwd + '/' + filename, 'w') as fp:
with open(cwd + '/' + filename, 'w', encoding="utf-8") as fp:
json.dump(bridge_config, fp, sort_keys=True, indent=4, separators=(',', ': '))
if docker:
Popen(["cp", cwd + '/' + filename, cwd + '/' + 'export/'])
Expand Down Expand Up @@ -1239,6 +1248,7 @@ def _set_end_headers(self, data):
def do_GET(self):
#Some older Philips Tv's sent non-standard HTTP GET requests with a Content-Lenght and a
# body. The HTTP body needs to be consumed and ignored in order to request be handle correctly.
global bridge_config
self.read_http_request_body()

if self.path == '/' or self.path == '/index.html':
Expand All @@ -1249,6 +1259,11 @@ def do_GET(self):
self._set_headers()
f = open(cwd + '/clip.html', 'rb')
self._set_end_headers(f.read())
elif self.path == "/factory-reset":
self._set_headers()
saveConfig('before-reset.json')
bridge_config = json.loads(requests.get('https://raw.githubusercontent.com/diyhue/diyHue/master/BridgeEmulator/config.json').text)
self._set_end_headers(bytes(json.dumps([{"success":{"configuration":"reset","backup-filename":"/opt/hue-emulator/before-reset.json"}}] ,separators=(',', ':'),ensure_ascii=False), "utf8"))
elif self.path == '/config.js':
self._set_headers()
#create a new user key in case none is available
Expand All @@ -1265,7 +1280,7 @@ def do_GET(self):
elif self.path == '/save':
self._set_headers()
saveConfig()
self._set_end_headers(bytes(json.dumps([{"success":{"configuration":"saved","filename":"/opt/hue-emulator/config.json"}}] ,separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"success":{"configuration":"saved","filename":"/opt/hue-emulator/config.json"}}] ,separators=(',', ':'),ensure_ascii=False), "utf8"))
elif self.path.startswith("/tradfri"): #setup Tradfri gateway
self._set_headers()
get_parameters = parse_qs(urlparse(self.path).query)
Expand Down Expand Up @@ -1458,13 +1473,13 @@ def do_GET(self):
bridge_config["config"]["whitelist"][url_pices[2]]["last use date"] = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
bridge_config["config"]["linkbutton"] = int(bridge_config["linkbutton"]["lastlinkbuttonpushed"]) + 30 >= int(datetime.now().strftime("%s"))
if len(url_pices) == 3: #print entire config
self._set_end_headers(bytes(json.dumps({"lights": bridge_config["lights"], "groups": bridge_config["groups"], "config": bridge_config["config"], "scenes": bridge_config["scenes"], "schedules": bridge_config["schedules"], "rules": bridge_config["rules"], "sensors": bridge_config["sensors"], "resourcelinks": bridge_config["resourcelinks"]},separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps({"lights": bridge_config["lights"], "groups": bridge_config["groups"], "config": bridge_config["config"], "scenes": bridge_config["scenes"], "schedules": bridge_config["schedules"], "rules": bridge_config["rules"], "sensors": bridge_config["sensors"], "resourcelinks": bridge_config["resourcelinks"]},separators=(',', ':'),ensure_ascii=False), "utf8"))
elif len(url_pices) == 4: #print specified object config
self._set_end_headers(bytes(json.dumps(bridge_config[url_pices[3]],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps(bridge_config[url_pices[3]],separators=(',', ':'),ensure_ascii=False), "utf8"))
elif len(url_pices) == 5:
if url_pices[4] == "new": #return new lights and sensors only
new_lights.update({"lastscan": datetime.now().strftime("%Y-%m-%dT%H:%M:%S")})
self._set_end_headers(bytes(json.dumps(new_lights ,separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps(new_lights ,separators=(',', ':'),ensure_ascii=False), "utf8"))
new_lights.clear()
elif url_pices[3] == "groups" and url_pices[4] == "0":
any_on = False
Expand All @@ -1474,15 +1489,15 @@ def do_GET(self):
any_on = True
else:
all_on = False
self._set_end_headers(bytes(json.dumps({"name":"Group 0","lights": [l for l in bridge_config["lights"]],"sensors": [s for s in bridge_config["sensors"]],"type":"LightGroup","state":{"all_on":all_on,"any_on":any_on},"recycle":False,"action":{"on":False,"alert":"none"}},separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps({"name":"Group 0","lights": [l for l in bridge_config["lights"]],"sensors": [s for s in bridge_config["sensors"]],"type":"LightGroup","state":{"all_on":all_on,"any_on":any_on},"recycle":False,"action":{"on":False,"alert":"none"}},separators=(',', ':'),ensure_ascii=False), "utf8"))
elif url_pices[3] == "info" and url_pices[4] == "timezones":
self._set_end_headers(bytes(json.dumps(bridge_config["capabilities"][url_pices[4]]["values"],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps(bridge_config["capabilities"][url_pices[4]]["values"],separators=(',', ':'),ensure_ascii=False), "utf8"),ensure_ascii=False)
else:
self._set_end_headers(bytes(json.dumps(bridge_config[url_pices[3]][url_pices[4]],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps(bridge_config[url_pices[3]][url_pices[4]],separators=(',', ':'),ensure_ascii=False), "utf8"))
elif (url_pices[2] == "nouser" or url_pices[2] == "none" or url_pices[2] == "config"): #used by applications to discover the bridge
self._set_end_headers(bytes(json.dumps({"name": bridge_config["config"]["name"],"datastoreversion": 70, "swversion": bridge_config["config"]["swversion"], "apiversion": bridge_config["config"]["apiversion"], "mac": bridge_config["config"]["mac"], "bridgeid": bridge_config["config"]["bridgeid"], "factorynew": False, "replacesbridgeid": None, "modelid": bridge_config["config"]["modelid"],"starterkitid":""},separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps({"name": bridge_config["config"]["name"],"datastoreversion": 70, "swversion": bridge_config["config"]["swversion"], "apiversion": bridge_config["config"]["apiversion"], "mac": bridge_config["config"]["mac"], "bridgeid": bridge_config["config"]["bridgeid"], "factorynew": False, "replacesbridgeid": None, "modelid": bridge_config["config"]["modelid"],"starterkitid":""},separators=(',', ':'),ensure_ascii=False), "utf8"))
else: #user is not in whitelist
self._set_end_headers(bytes(json.dumps([{"error": {"type": 1, "address": self.path, "description": "unauthorized user" }}],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"error": {"type": 1, "address": self.path, "description": "unauthorized user" }}],separators=(',', ':'),ensure_ascii=False), "utf8"))

def read_http_request_body(self):
return b"{}" if self.headers['Content-Length'] is None or self.headers[
Expand All @@ -1500,7 +1515,7 @@ def do_POST(self):
for key in update_data[category].keys():
logging.info("patch " + category + " -> " + key )
bridge_config[category][key] = update_data[category][key]
self._set_end_headers(bytes(json.dumps([{"success": {"/config/swupdate/checkforupdate": True}}],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"success": {"/config/swupdate/checkforupdate": True}}],separators=(',', ':'),ensure_ascii=False), "utf8"))
else:
raw_json = self.data_string.decode('utf8')
raw_json = raw_json.replace("\t","")
Expand All @@ -1514,9 +1529,9 @@ def do_POST(self):
#if was a request to scan for lights of sensors
Thread(target=scanForLights).start()
sleep(7) #give no more than 5 seconds for light scanning (otherwise will face app disconnection timeout)
self._set_end_headers(bytes(json.dumps([{"success": {"/" + url_pices[3]: "Searching for new devices"}}],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"success": {"/" + url_pices[3]: "Searching for new devices"}}],separators=(',', ':'),ensure_ascii=False), "utf8"))
elif url_pices[3] == "":
self._set_end_headers(bytes(json.dumps([{"success": {"clientkey": "321c0c2ebfa7361e55491095b2f5f9db"}}],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"success": {"clientkey": "321c0c2ebfa7361e55491095b2f5f9db"}}],separators=(',', ':'),ensure_ascii=False), "utf8"))
else: #create object
# find the first unused id for new object
new_object_id = nextFreeId(bridge_config, url_pices[3])
Expand Down Expand Up @@ -1551,9 +1566,9 @@ def do_POST(self):
generateSensorsState()
bridge_config[url_pices[3]][new_object_id] = post_dictionary
logging.info(json.dumps([{"success": {"id": new_object_id}}], sort_keys=True, indent=4, separators=(',', ': ')))
self._set_end_headers(bytes(json.dumps([{"success": {"id": new_object_id}}], separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"success": {"id": new_object_id}}], separators=(',', ':'),ensure_ascii=False), "utf8"))
else:
self._set_end_headers(bytes(json.dumps([{"error": {"type": 1, "address": self.path, "description": "unauthorized user" }}], separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"error": {"type": 1, "address": self.path, "description": "unauthorized user" }}], separators=(',', ':'),ensure_ascii=False), "utf8"))
logging.info(json.dumps([{"error": {"type": 1, "address": self.path, "description": "unauthorized user" }}],sort_keys=True, indent=4, separators=(',', ': ')))
elif self.path.startswith("/api") and "devicetype" in post_dictionary: #new registration by linkbutton
if int(bridge_config["linkbutton"]["lastlinkbuttonpushed"])+30 >= int(datetime.now().strftime("%s")) or bridge_config["config"]["linkbutton"]:
Expand All @@ -1562,10 +1577,10 @@ def do_POST(self):
response = [{"success": {"username": username}}]
if "generateclientkey" in post_dictionary and post_dictionary["generateclientkey"]:
response[0]["success"]["clientkey"] = "321c0c2ebfa7361e55491095b2f5f9db"
self._set_end_headers(bytes(json.dumps(response,separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps(response,separators=(',', ':'),ensure_ascii=False), "utf8"))
logging.info(json.dumps(response, sort_keys=True, indent=4, separators=(',', ': ')))
else:
self._set_end_headers(bytes(json.dumps([{"error": {"type": 101, "address": self.path, "description": "link button not pressed" }}], separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"error": {"type": 101, "address": self.path, "description": "link button not pressed" }}], separators=(',', ':'),ensure_ascii=False), "utf8"))
saveConfig()

def do_PUT(self):
Expand Down Expand Up @@ -1634,7 +1649,7 @@ def do_PUT(self):

#add exception on json output as this dictionary has tree levels
response_dictionary = {"success":{"/lights/" + url_pices[4] + "/config/startup": {"mode": put_dictionary["config"]["startup"]["mode"]}}}
self._set_end_headers(bytes(json.dumps(response_dictionary,separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps(response_dictionary,separators=(',', ':'),ensure_ascii=False), "utf8"))
logging.info(json.dumps(response_dictionary, sort_keys=True, indent=4, separators=(',', ': ')))
return
else:
Expand Down Expand Up @@ -1698,10 +1713,10 @@ def do_PUT(self):
response_dictionary = []
for key, value in put_dictionary.items():
response_dictionary.append({"success":{response_location + key: value}})
self._set_end_headers(bytes(json.dumps(response_dictionary,separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps(response_dictionary,separators=(',', ':'),ensure_ascii=False), "utf8"))
logging.info(json.dumps(response_dictionary, sort_keys=True, indent=4, separators=(',', ': ')))
else:
self._set_end_headers(bytes(json.dumps([{"error": {"type": 1, "address": self.path, "description": "unauthorized user" }}],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"error": {"type": 1, "address": self.path, "description": "unauthorized user" }}],separators=(',', ':'),ensure_ascii=False), "utf8"))

def do_DELETE(self):
self._set_headers()
Expand Down Expand Up @@ -1734,7 +1749,7 @@ def do_DELETE(self):
for sensor in list(bridge_config["deconz"]["sensors"]):
if bridge_config["deconz"]["sensors"][sensor]["bridgeid"] == url_pices[4]:
del bridge_config["deconz"]["sensors"][sensor]
self._set_end_headers(bytes(json.dumps([{"success": "/" + url_pices[3] + "/" + url_pices[4] + " deleted."}],separators=(',', ':')), "utf8"))
self._set_end_headers(bytes(json.dumps([{"success": "/" + url_pices[3] + "/" + url_pices[4] + " deleted."}],separators=(',', ':'),ensure_ascii=False), "utf8"))

class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
pass
Expand Down

0 comments on commit 07bed23

Please sign in to comment.