Skip to content

Commit

Permalink
Big update
Browse files Browse the repository at this point in the history
Add sub-ip-range to light scan.
Move deprecate command line arguments ip-range, scan-on-host-ip, deconz, disable-online-discover, TZ to bridgeConfig and WebUI.
Add check if a valid MAC address is provided.
Make sensitive info privately.
Move from create-react-app to vite.
Add the option to remove the certificate.
Update V1api scan for devices request.
Add temporary log level change in WebUI.
Add FPS counter to entertainment.
  • Loading branch information
hendriksen-mark committed Nov 17, 2024
1 parent 58aa81c commit e67e27f
Show file tree
Hide file tree
Showing 1,733 changed files with 184 additions and 118 deletions.
4 changes: 2 additions & 2 deletions .build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ RUN curl -sL https://github.com/diyhue/diyHueUI/releases/latest/download/DiyHueU
&& mkdir diyhueUI \
&& unzip -qo diyHueUI.zip -d diyhueUI \
&& rm diyHueUI.zip \
&& mv diyhueUI/index.html flaskUI/templates/ \
&& cp -r diyhueUI/static flaskUI/ \
&& mv diyhueUI/dist/index.html flaskUI/templates/ \
&& cp -r diyhueUI/dist/assets flaskUI/ \
&& rm -r diyhueUI

## Copy correct (compiled) C file from previous image
Expand Down
2 changes: 1 addition & 1 deletion BridgeEmulator/HueEmulator3.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
logging = logManager.logger.get_logger(__name__)
_ = logManager.logger.get_logger("werkzeug")
WSGIRequestHandler.protocol_version = "HTTP/1.1"
app = Flask(__name__, template_folder='flaskUI/templates',static_url_path="/static", static_folder='flaskUI/static')
app = Flask(__name__, template_folder='flaskUI/templates',static_url_path="/assets", static_folder='flaskUI/assets')
api = Api(app)
cors = CORS(app, resources={r"*": {"origins": "*"}})

Expand Down
20 changes: 15 additions & 5 deletions BridgeEmulator/HueObjects/Light.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ def __init__(self, data):
self.modelid = data["modelid"]
self.id_v1 = data["id_v1"]
self.id_v2 = data["id_v2"] if "id_v2" in data else genV2Uuid()
self.uniqueid = data["uniqueid"] if "uniqueid" in data else generate_unique_id(
)
self.uniqueid = data["uniqueid"] if "uniqueid" in data else generate_unique_id()
self.state = data["state"] if "state" in data else deepcopy(
lightTypes[self.modelid]["state"])
self.protocol = data["protocol"] if "protocol" in data else "dummy"
self.config = data["config"] if "config" in data else deepcopy(
lightTypes[self.modelid]["config"])
self.protocol_cfg = data["protocol_cfg"] if "protocol_cfg" in data else {
}
self.protocol_cfg = data["protocol_cfg"] if "protocol_cfg" in data else {}
self.streaming = False
self.dynamics = deepcopy(lightTypes[self.modelid]["dynamics"])
self.effect = "no_effect"
Expand Down Expand Up @@ -359,7 +357,19 @@ def getV2Api(self):
result["signaling"] = {"signal_values": [
"no_signal",
"on_off"]}
result["powerup"] = {"preset": "last_on_state"}
result["powerup"] = {
"preset": "last_on_state",
"configured": True,
"on": {
"mode": "on",
"on": {
"on": True
}
},
"dimming": {
"mode": "previous"
}
}
result["service_id"] = self.protocol_cfg["light_nr"]-1 if "light_nr" in self.protocol_cfg else 0
result["type"] = "light"
return result
Expand Down
86 changes: 28 additions & 58 deletions BridgeEmulator/configManager/argumentHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ def process_arguments(configDir, args):

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, "TZ": ''}
"noLinkButton": False, "noServeHttps": False}
ap = argparse.ArgumentParser()

# Arguements can also be passed as Environment Variables.
Expand All @@ -49,19 +48,19 @@ def parse_arguments():
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("--ip-range", help="Deprecated use webui, Set IP range for light discovery. Format: <START_IP>,<STOP_IP>", type=str)
ap.add_argument("--sub-ip-range", help="Deprecated use webui, Set SUB IP range for light discovery. Format: <START_IP>,<STOP_IP>", type=str)
ap.add_argument("--scan-on-host-ip", action='store_true', help="Deprecated use webui, Scan the local IP address when discovering new lights")
ap.add_argument("--deconz", help="Deprecated use webui, 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")
ap.add_argument("--TZ", help="Set time zone", type=str)
ap.add_argument("--disable-online-discover", help="Deprecated use webui, Disable Online and Remote API functions")
ap.add_argument("--TZ", help="Deprecated use webui, Set time zone", type=str)

args = ap.parse_args()

if args.scan_on_host_ip:
argumentDict["scanOnHostIP"] = True
logging.warn("scan_on_host_ip is Deprecated in commandline and not active, please setup via webui")

if args.no_link_button:
argumentDict["noLinkButton"] = True
Expand All @@ -72,26 +71,24 @@ def parse_arguments():
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')
else:
config_path = '/opt/hue-emulator/config'
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')
else:
bind_ip = '0.0.0.0'
argumentDict["BIND_IP"] = bind_ip

tz = "Europe/London"
if args.TZ:
tz = args.TZ
elif get_environment_variable('TZ'):
tz = get_environment_variable('TZ')
argumentDict["TZ"] = tz
if args.TZ or get_environment_variable('TZ'):
logging.warn("Time Zone is Deprecated in commandline and not active, please setup via webui")

if args.ip:
host_ip = args.ip
Expand Down Expand Up @@ -120,11 +117,12 @@ def parse_arguments():
argumentDict["HTTPS_PORT"] = host_https_port

logging.info("Using Host %s:%s" % (host_ip, host_http_port))
logging.info("Using Host %s:%s" % (host_ip, host_https_port))

if args.mac:
if args.mac and str(args.mac).replace(":", "").capitalize != "XXXXXXXXXXXX":
dockerMAC = args.mac # keeps : for cert generation
mac = str(args.mac).replace(":", "")
elif get_environment_variable('MAC'):
elif get_environment_variable('MAC') and get_environment_variable('MAC').strip('\u200e').replace(":", "").capitalize != "XXXXXXXXXXXX":
dockerMAC = get_environment_variable('MAC').strip('\u200e')
mac = str(dockerMAC).replace(":", "")
else:
Expand All @@ -139,49 +137,21 @@ def parse_arguments():
argumentDict["FULLMAC"] = dockerMAC
argumentDict["MAC"] = mac
argumentDict["DOCKER"] = docker
logging.info("Host MAC given as " + mac)
if mac.capitalize == "XXXXXXXXXXXX" or mac == "":
logging.exception("No valid MAC address provided " + str(mac))
logging.exception("To fix this visit: https://diyhue.readthedocs.io/en/latest/getting_started.html")
raise SystemExit("CRITICAL! No valid MAC address provided " + str(mac))
else:
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 args.ip_range or get_environment_variable('IP_RANGE') or args.sub_ip_range or get_environment_variable('IP_RANGE_START') and get_environment_variable('IP_RANGE_END') or get_environment_variable('SUB_IP_RANGE') or get_environment_variable('SUB_IP_RANGE_START') or get_environment_variable('SUB_IP_RANGE_END'):
logging.warn("IP range is Deprecated in commandline and not active, please setup via webui")

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.deconz or get_environment_variable('DECONZ'):
logging.warn("DECONZ is Deprecated in commandline and not active, please setup via webui")

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
logging.warn("disableonlinediscover is Deprecated in commandline and not active, please setup via webui")

if argumentDict['noServeHttps']:
logging.info("HTTPS Port Disabled")
Expand Down
57 changes: 51 additions & 6 deletions BridgeEmulator/configManager/configHandler.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from configManager import configInit
from configManager.argumentHandler import parse_arguments
from configManager.argumentHandler import parse_arguments, generate_certificate
import os
import pathlib
import subprocess
import logManager
import yaml
import uuid
import weakref
from copy import deepcopy
from HueObjects import Light, Group, EntertainmentConfiguration, Scene, ApiUser, Rule, ResourceLink, Schedule, Sensor, BehaviorInstance, SmartScene
try:
from time import tzset
Expand All @@ -30,7 +31,8 @@ def _write_yaml(path, contents):

class Config:
yaml_config = None
configDir = parse_arguments()["CONFIG_PATH"]
argsDict = parse_arguments()
configDir = argsDict["CONFIG_PATH"]
runningDir = str(pathlib.Path(__file__)).replace("/configManager/configHandler.py","")

def __init__(self):
Expand All @@ -43,6 +45,9 @@ def load_config(self):
#load config
if os.path.exists(self.configDir + "/config.yaml"):
config = _open_yaml(self.configDir + "/config.yaml")
if "timezone" not in config:
logging.warn("No Time Zone in config, please set Time Zone in webui, default to Europe/London")
config["timezone"] = "Europe/London"
os.environ['TZ'] = config["timezone"]
if tzset is not None:
tzset()
Expand All @@ -51,6 +56,16 @@ def load_config(self):
self.yaml_config["apiUsers"][user] = ApiUser.ApiUser(user, data["name"], data["client_key"], data["create_date"], data["last_use_date"])
del config["whitelist"]
# updgrade config
if "discovery" not in config:
config["discovery"] = True
if "IP_RANGE" not in config:
config["IP_RANGE"] = {
"IP_RANGE_START": 0,
"IP_RANGE_END": 255,
"SUB_IP_RANGE_START": int(self.argsDict["HOST_IP"].split('.')[2]),
"SUB_IP_RANGE_END": int(self.argsDict["HOST_IP"].split('.')[2])}
if "scanonhostip" not in config:
config["scanonhostip"] = False
if "homeassistant" not in config:
config["homeassistant"] = {"enabled": False}
if "yeelight" not in config:
Expand Down Expand Up @@ -101,6 +116,7 @@ def load_config(self):
"Remote API enabled": False,
"Hue Essentials key": str(uuid.uuid1()).replace('-', ''),
"discovery": True,
"scanonhostip": False,
"mqtt":{"enabled":False},
"deconz":{"enabled":False},
"alarm":{"enabled": False,"lasttriggered": 0},
Expand All @@ -110,7 +126,7 @@ def load_config(self):
"name":"DiyHue Bridge",
"netmask":"255.255.255.0",
"swversion":"1965111030",
"timezone":parse_arguments()["TZ"],
"timezone": "Europe/London",
"linkbutton":{"lastlinkbuttonpushed": 1599398980},
"users":{"admin@diyhue.org":{"password":"pbkdf2:sha256:150000$bqqXSOkI$199acdaf81c18f6ff2f29296872356f4eb78827784ce4b3f3b6262589c788742"}},
"hue": {},
Expand Down Expand Up @@ -138,7 +154,13 @@ def load_config(self):
"lastchange": "2020-12-13T10:30:15",
"state": "noupdates",
"install": False
}
},
"IP_RANGE": {
"IP_RANGE_START": 0,
"IP_RANGE_END": 255,
"SUB_IP_RANGE_START": int(self.argsDict["HOST_IP"].split('.')[2]),
"SUB_IP_RANGE_END": int(self.argsDict["HOST_IP"].split('.')[2])
}
}
# load lights
if os.path.exists(self.configDir + "/lights.yaml"):
Expand Down Expand Up @@ -287,6 +309,15 @@ def reset_config(self):
self.load_config()
return backup

def remove_cert(self):
try:
os.popen('mv ' + self.configDir + '/cert.pem ' + self.configDir + '/backup/')
logging.info("Certificate removed")
except:
logging.exception("Something went wrong when deleting the certificate")
generate_certificate(self.argsDict["MAC"], self.argsDict["CONFIG_PATH"])
return

def restore_backup(self):
try:
os.popen('rm -r ' + self.configDir + '/*.yaml')
Expand All @@ -308,18 +339,32 @@ def download_log(self):
return self.configDir + "/diyhue_log.tar"

def download_debug(self):
_write_yaml(self.configDir + "/config_debug.yaml", self.yaml_config["config"])
debug = _open_yaml(self.configDir + "/config_debug.yaml")
#_write_yaml(self.configDir + "/config_debug.yaml", self.yaml_config["config"])
#debug = _open_yaml(self.configDir + "/config_debug.yaml")
debug = deepcopy(self.yaml_config["config"])
debug["whitelist"] = "privately"
debug["apiUsers"] = "privately"
debug["Hue Essentials key"] = "privately"
debug["users"] = "privately"
if debug["mqtt"]["enabled"]:
debug["mqtt"]["mqttPassword"] = "privately"
if debug["homeassistant"]["enabled"]:
debug["homeassistant"]["homeAssistantToken"] = "privately"
if debug["hue"]:
debug["hue"]["hueUser"] = "privately"
debug["hue"]["hueKey"] = "privately"
if debug["tradfri"]:
debug["tradfri"]["psk"] = "privately"
if debug["alarm"]["enabled"]:
debug["alarm"]["email"] = "privately"
info = {}
info["OS"] = os.uname().sysname
info["Architecture"] = os.uname().machine
info["os_version"] = os.uname().version
info["os_release"] = os.uname().release
info["Hue-Emulator Version"] = subprocess.run("stat -c %y HueEmulator3.py", shell=True, capture_output=True, text=True).stdout.replace("\n", "")
info["WebUI Version"] = subprocess.run("stat -c %y flaskUI/templates/index.html", shell=True, capture_output=True, text=True).stdout.replace("\n", "")
info["arguments"] = self.argsDict
_write_yaml(self.configDir + "/config_debug.yaml", debug)
_write_yaml(self.configDir + "/system_info.yaml", info)
subprocess.run('tar --exclude=' + "'config.yaml'" + ' -cvf ' + self.configDir + '/config_debug.tar ' +
Expand Down
Loading

0 comments on commit e67e27f

Please sign in to comment.