diff --git a/data/internal_config/ssdp.json b/data/internal_config/ssdp.json index abe84b2..02cfdb0 100644 --- a/data/internal_config/ssdp.json +++ b/data/internal_config/ssdp.json @@ -5,10 +5,25 @@ "config_file": true, "config_web": false }, - "refresh_frequency":{ + "max_age":{ "value": 1800, "config_file": true, "config_web": false - } + }, + "proto":{ + "value": "ipv4", + "config_file": true, + "config_web": false + }, + "iface":{ + "value": "none", + "config_file": true, + "config_web": false + }, + "multicast_address":{ + "value": "none", + "config_file": true, + "config_web": false + } } } diff --git a/fHDHR/__init__.py b/fHDHR/__init__.py index a8e9384..5e40adc 100644 --- a/fHDHR/__init__.py +++ b/fHDHR/__init__.py @@ -2,6 +2,7 @@ from .originwrapper import OriginServiceWrapper from .device import fHDHR_Device +from .api import fHDHR_API_URLs import fHDHR.tools @@ -18,6 +19,8 @@ class fHDHR_INT_OBJ(): self.web = fHDHR.tools.WebReq() + self.api = fHDHR_API_URLs(settings) + class fHDHR_OBJ(): diff --git a/fHDHR/api/__init__.py b/fHDHR/api/__init__.py new file mode 100644 index 0000000..17aae97 --- /dev/null +++ b/fHDHR/api/__init__.py @@ -0,0 +1,36 @@ +import urllib.parse + + +class fHDHR_API_URLs(): + + def __init__(self, settings): + self.config = settings + + self.address = self.config.dict["fhdhr"]["address"] + self.discovery_address = self.config.dict["fhdhr"]["discovery_address"] + self.port = self.config.dict["fhdhr"]["port"] + + @property + def base(self): + if self.discovery_address: + return ('http://%s:%s' % self.discovery_address_tuple) + elif self.address == "0.0.0.0": + return ('http://%s:%s' % self.address_tuple) + else: + return ('http://%s:%s' % self.address_tuple) + + @property + def base_quoted(self): + return urllib.parse.quote(self.base) + + @property + def discovery_address_tuple(self): + return (self.discovery_address, int(self.port)) + + @property + def localhost_address_tuple(self): + return ("127.0.0.1", int(self.port)) + + @property + def address_tuple(self): + return (self.address, int(self.port)) diff --git a/fHDHR/device/cluster.py b/fHDHR/device/cluster.py index 3a6e629..4d5a5ab 100644 --- a/fHDHR/device/cluster.py +++ b/fHDHR/device/cluster.py @@ -1,4 +1,3 @@ -import urllib.parse from collections import OrderedDict @@ -10,14 +9,8 @@ class fHDHR_Cluster(): self.ssdp = ssdp self.friendlyname = self.fhdhr.config.dict["fhdhr"]["friendlyname"] - self.location = None - self.location_url = None - - if fhdhr.config.dict["fhdhr"]["discovery_address"]: - self.location = ('http://' + fhdhr.config.dict["fhdhr"]["discovery_address"] + ':' + - str(fhdhr.config.dict["fhdhr"]["port"])) - self.location_url = urllib.parse.quote(self.location) + if self.fhdhr.config.dict["fhdhr"]["discovery_address"]: self.startup_sync() def cluster(self): @@ -31,7 +24,7 @@ class fHDHR_Cluster(): "base_url": fhdhr_list[location]["base_url"], "name": fhdhr_list[location]["name"] } - if item_dict["base_url"] != self.location: + if item_dict["base_url"] != self.fhdhr.api.base: locations.append(item_dict) if len(locations): locations = sorted(locations, key=lambda i: i['name']) @@ -43,7 +36,7 @@ class fHDHR_Cluster(): cluster = self.fhdhr.db.get_fhdhr_value("cluster", "dict") or self.default_cluster() return_dict = {} for location in list(cluster.keys()): - if location != self.location: + if location != self.fhdhr.api.base: return_dict[location] = { "Joined": True } @@ -59,8 +52,8 @@ class fHDHR_Cluster(): def default_cluster(self): defdict = {} - defdict[self.location] = { - "base_url": self.location, + defdict[self.fhdhr.api.base] = { + "base_url": self.fhdhr.api.base, "name": self.friendlyname } return defdict @@ -73,13 +66,13 @@ class fHDHR_Cluster(): else: self.fhdhr.logger.info("Found %s clustered services." % str(len(list(cluster.keys())))) for location in list(cluster.keys()): - if location != self.location: + if location != self.fhdhr.api.base: self.fhdhr.logger.info("Checking Cluster Syncronization information from %s." % location) sync_url = location + "/api/cluster?method=get" try: sync_open = self.fhdhr.web.session.get(sync_url) retrieved_cluster = sync_open.json() - if self.location not in list(retrieved_cluster.keys()): + if self.fhdhr.api.base not in list(retrieved_cluster.keys()): return self.leave() except self.fhdhr.web.exceptions.ConnectionError: self.fhdhr.logger.error("Unreachable: " + location) @@ -91,9 +84,9 @@ class fHDHR_Cluster(): def disconnect(self): cluster = self.fhdhr.db.get_fhdhr_value("cluster", "dict") or self.default_cluster() for location in list(cluster.keys()): - if location != self.location: + if location != self.fhdhr.api.base: self.fhdhr.logger.info("Informing %s that I am departing the Cluster." % location) - sync_url = location + "/api/cluster?method=del&location=" + self.location + sync_url = location + "/api/cluster?method=del&location=" + self.fhdhr.api.base try: self.fhdhr.web.session.get(sync_url) except self.fhdhr.web.exceptions.ConnectionError: @@ -111,8 +104,8 @@ class fHDHR_Cluster(): def push_sync(self): cluster = self.fhdhr.db.get_fhdhr_value("cluster", "dict") or self.default_cluster() for location in list(cluster.keys()): - if location != self.location: - sync_url = location + "/api/cluster?method=sync&location=" + self.location_url + if location != self.fhdhr.api.base: + sync_url = location + "/api/cluster?method=sync&location=" + self.fhdhr.api.base_quoted try: self.fhdhr.web.session.get(sync_url) except self.fhdhr.web.exceptions.ConnectionError: diff --git a/fHDHR/device/epg/__init__.py b/fHDHR/device/epg/__init__.py index 4d7e817..2804730 100644 --- a/fHDHR/device/epg/__init__.py +++ b/fHDHR/device/epg/__init__.py @@ -36,12 +36,7 @@ class EPG(): if epg_method not in list(self.sleeptime.keys()): self.sleeptime[epg_method] = self.fhdhr.config.dict["epg"]["update_frequency"] - if self.fhdhr.config.dict["fhdhr"]["address"] == "0.0.0.0": - self.location = ('http://127.0.0.1:%s' % str(self.fhdhr.config.dict["fhdhr"]["port"])) - else: - self.location = ('http://%s:%s' % (self.fhdhr.config.dict["fhdhr"]["address"], str(self.fhdhr.config.dict["fhdhr"]["port"]))) - - self.epg_update_url = "%s/api/epg?method=update" % (self.location) + self.epg_update_url = "%s/api/epg?method=update" % (self.fhdhr.api.base) def clear_epg_cache(self, method=None): diff --git a/fHDHR/device/ssdp/__init__.py b/fHDHR/device/ssdp/__init__.py index ed317d8..c095325 100644 --- a/fHDHR/device/ssdp/__init__.py +++ b/fHDHR/device/ssdp/__init__.py @@ -15,79 +15,19 @@ class SSDPServer(): self.detect_method = fHDHR_Detect(fhdhr) - if (fhdhr.config.dict["fhdhr"]["discovery_address"] and - fhdhr.config.dict["ssdp"]["enabled"]): + if (self.fhdhr.config.dict["fhdhr"]["discovery_address"] and + self.fhdhr.config.dict["ssdp"]["enabled"]): + self.setup_ssdp() - self.sock = None - self.proto = "ipv4" - self.port = 1900 - self.iface = None - self.address = None - - allowed_protos = ("ipv4", "ipv6") - if self.proto not in allowed_protos: - raise ValueError("Invalid proto - expected one of {}".format(allowed_protos)) - - self.location = ('http://' + fhdhr.config.dict["fhdhr"]["discovery_address"] + ':' + - str(fhdhr.config.dict["fhdhr"]["port"]) + '/device.xml') - - self._iface = None - - if self.proto == "ipv4": - self._af_type = socket.AF_INET - self._broadcast_ip = "239.255.255.250" - self._address = (self._broadcast_ip, self.port) - self.bind_address = "0.0.0.0" - elif self.proto == "ipv6": - self._af_type = socket.AF_INET6 - self._broadcast_ip = "ff02::c" - self._address = (self._broadcast_ip, self.port, 0, 0) - self.bind_address = "::" - - self.broadcast_addy = "{}:{}".format(self._broadcast_ip, self.port) - - self.sock = socket.socket(self._af_type, socket.SOCK_DGRAM, socket.IPPROTO_UDP) - self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - # Bind to specific interface - if self.iface is not None: - self.sock.setsockopt(socket.SOL_SOCKET, getattr(socket, "SO_BINDTODEVICE", 25), self.iface) - - # Subscribe to multicast address - if self.proto == "ipv4": - mreq = socket.inet_aton(self._broadcast_ip) - if self.address is not None: - mreq += socket.inet_aton(self.address) - else: - mreq += struct.pack(b"@I", socket.INADDR_ANY) - self.sock.setsockopt( - socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq, - ) - # Allow multicasts on loopback devices (necessary for testing) - self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1) - elif self.proto == "ipv6": - # In IPv6 we use the interface index, not the address when subscribing to the group - mreq = socket.inet_pton(socket.AF_INET6, self._broadcast_ip) - if self.iface is not None: - iface_index = socket.if_nametoindex(self.iface) - # Send outgoing packets from the same interface - self.sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, iface_index) - mreq += struct.pack(b"@I", iface_index) - else: - mreq += socket.inet_pton(socket.AF_INET6, "::") - self.sock.setsockopt( - socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq, - ) - self.sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, 1) - self.sock.bind((self.bind_address, self.port)) + self.sock.bind((self.bind_address, 1900)) self.msearch_payload = self.create_msearch_payload() - self.rmg_ssdp = RMG_SSDP(fhdhr, self._broadcast_ip) - self.hdhr_ssdp = HDHR_SSDP(fhdhr, self._broadcast_ip) + self.max_age = int(fhdhr.config.dict["ssdp"]["max_age"]) + self.age_time = None - self.refresh = int(fhdhr.config.dict["ssdp"]["refresh_frequency"]) - self.refresh_last = None + self.rmg_ssdp = RMG_SSDP(fhdhr, self.broadcast_ip, self.max_age) + self.hdhr_ssdp = HDHR_SSDP(fhdhr, self.broadcast_ip, self.max_age) self.do_alive() self.m_search() @@ -95,17 +35,17 @@ class SSDPServer(): def do_alive(self, forcealive=False): send_alive = False - if not self.refresh_last: + if not self.age_time: send_alive = True elif forcealive: send_alive = True - elif time.time() >= (self.refresh_last + self.refresh): + elif time.time() >= (self.age_time + self.max_age): send_alive = True if send_alive: self.fhdhr.logger.info("Sending Alive message to network.") - self.do_notify(('239.255.255.250', 1900)) - self.refresh_last = time.time() + self.do_notify(self.broadcase_address_tuple) + self.age_time = time.time() def do_notify(self, address): @@ -118,11 +58,11 @@ class SSDPServer(): rmg_notify = self.rmg_ssdp.get() notify_list.append(rmg_notify) - for notify in notify_list: + for notifydata in notify_list: - self.fhdhr.logger.debug("Created {}".format(notify)) + self.fhdhr.logger.debug("Created {}".format(notifydata)) try: - self.sock.sendto(notify, address) + self.sock.sendto(notifydata, address) except OSError as e: # Most commonly: We received a multicast from an IP not in our subnet self.fhdhr.logger.debug("Unable to send NOTIFY: %s" % e) @@ -157,12 +97,12 @@ class SSDPServer(): self.fhdhr.logger.debug("NOTIFY data: {}".format(headers)) try: if headers["server"].startswith("fHDHR"): - if headers["location"] != self.location: - savelocation = headers["location"].split("/device.xml")[0] - if savelocation.endswith("/hdhr"): - savelocation = savelocation.replace("/hdhr", '') - elif savelocation.endswith("/rmg"): - savelocation = savelocation.replace("/rmg", '') + savelocation = headers["location"].split("/device.xml")[0] + if savelocation.endswith("/hdhr"): + savelocation = savelocation.replace("/hdhr", '') + elif savelocation.endswith("/rmg"): + savelocation = savelocation.replace("/rmg", '') + if savelocation != self.fhdhr.api.base: self.detect_method.set(savelocation) except KeyError: return @@ -171,21 +111,25 @@ class SSDPServer(): def m_search(self): data = self.msearch_payload - self.sock.sendto(data, self._address) + self.sock.sendto(data, self.broadcase_address_tuple) def create_msearch_payload(self): - data = ( - "M-SEARCH * HTTP/1.1\r\n" - "HOST:{}\r\n" - 'MAN: "ssdp:discover"\r\n' - "ST:{}\r\n" - "MX:{}\r\n" - ).format( - self.broadcast_addy, - "ssdp:all", - 1 - ) + + data = '' + data_command = "M-SEARCH * HTTP/1.1" + + data_dict = { + "HOST": "%s:%s" % (self.broadcast_ip, 1900), + "MAN": "ssdp:discover", + "ST": "ssdp:all", + "MX": 1, + } + + data += "%s\r\n" % data_command + for data_key in list(data_dict.keys()): + data += "%s:%s\r\n" % (data_key, data_dict[data_key]) data += "\r\n" + return data.encode("utf-8") def run(self): @@ -196,3 +140,69 @@ class SSDPServer(): self.do_alive() except KeyboardInterrupt: self.sock.close() + + def setup_ssdp(self): + self.sock = None + + self.proto = self.setup_proto() + self.iface = self.fhdhr.config.dict["ssdp"]["iface"] + self.address = self.fhdhr.config.dict["ssdp"]["multicast_address"] + self.setup_addressing() + + self.sock = socket.socket(self.af_type, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + self.setup_interface() + + self.setup_multicasting() + + def setup_proto(self): + proto = self.fhdhr.config.dict["ssdp"]["proto"] + allowed_protos = ("ipv4", "ipv6") + if proto not in allowed_protos: + raise ValueError("Invalid proto - expected one of {}".format(allowed_protos)) + return proto + + def setup_addressing(self): + if self.proto == "ipv4": + self.af_type = socket.AF_INET + self.broadcast_ip = "239.255.255.250" + self.broadcase_address_tuple = (self.broadcast_ip, 1900) + self.bind_address = "0.0.0.0" + elif self.proto == "ipv6": + self.af_type = socket.AF_INET6 + self.broadcast_ip = "ff02::c" + self.broadcast_address_tuple = (self.broadcast_ip, 1900, 0, 0) + self.bind_address = "::" + + def setup_interface(self): + # Bind to specific interface + if self.iface is not None: + self.sock.setsockopt(socket.SOL_SOCKET, getattr(socket, "SO_BINDTODEVICE", 25), self.iface) + + def setup_multicasting(self): + # Subscribe to multicast address + if self.proto == "ipv4": + mreq = socket.inet_aton(self.broadcast_ip) + if self.address is not None: + mreq += socket.inet_aton(self.address) + else: + mreq += struct.pack(b"@I", socket.INADDR_ANY) + self.sock.setsockopt( + socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) + # Allow multicasts on loopback devices (necessary for testing) + self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1) + elif self.proto == "ipv6": + # In IPv6 we use the interface index, not the address when subscribing to the group + mreq = socket.inet_pton(socket.AF_INET6, self.broadcast_ip) + if self.iface is not None: + iface_index = socket.if_nametoindex(self.iface) + # Send outgoing packets from the same interface + self.sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, iface_index) + mreq += struct.pack(b"@I", iface_index) + else: + mreq += socket.inet_pton(socket.AF_INET6, "::") + self.sock.setsockopt( + socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq, + ) + self.sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, 1) diff --git a/fHDHR/device/ssdp/hdhr_ssdp.py b/fHDHR/device/ssdp/hdhr_ssdp.py index 7f8cb11..b9f4e36 100644 --- a/fHDHR/device/ssdp/hdhr_ssdp.py +++ b/fHDHR/device/ssdp/hdhr_ssdp.py @@ -2,43 +2,38 @@ class HDHR_SSDP(): - def __init__(self, fhdhr, _broadcast_ip): + def __init__(self, fhdhr, broadcast_ip, max_age): self.fhdhr = fhdhr self.ssdp_content = None - self._broadcast_ip = _broadcast_ip - self.nt = 'urn:schemas-upnp-org:device:MediaServer:1' - self.usn = 'uuid:' + fhdhr.config.dict["main"]["uuid"] + '::' + self.nt - self.server = 'fHDHR/%s UPnP/1.0' % fhdhr.version - self.location = ('http://' + fhdhr.config.dict["fhdhr"]["discovery_address"] + ':' + - str(fhdhr.config.dict["fhdhr"]["port"]) + '/device.xml') - self.al = self.location - self.max_age = 1800 + self.broadcast_ip = broadcast_ip + self.device_xml_path = '/device.xml' + + self.max_age = max_age def get(self): if self.ssdp_content: return self.ssdp_content.encode("utf-8") - data = ( - "NOTIFY * HTTP/1.1\r\n" - "HOST:{}\r\n" - "NT:{}\r\n" - "NTS:ssdp:alive\r\n" - "USN:{}\r\n" - "SERVER:{}\r\n" - ).format( - self._broadcast_ip, - self.nt, - self.usn, - self.server - ) - if self.location is not None: - data += "LOCATION:{}\r\n".format(self.location) - if self.al is not None: - data += "AL:{}\r\n".format(self.al) - if self.max_age is not None: - data += "Cache-Control:max-age={}\r\n".format(self.max_age) + data = '' + data_command = "NOTIFY * HTTP/1.1" + + data_dict = { + "HOST": "%s:%s" % (self.broadcast_ip, 1900), + "NT": 'urn:schemas-upnp-org:device:MediaServer:1', + "NTS": "ssdp:alive", + "USN": 'uuid:%s::%s' % (self.fhdhr.config.dict["main"]["uuid"], 'urn:schemas-upnp-org:device:MediaServer:1'), + "SERVER": 'fHDHR/%s UPnP/1.0' % self.fhdhr.version, + "LOCATION": "%s%s" % (self.fhdhr.api.base, self.device_xml_path), + "AL": "%s%s" % (self.fhdhr.api.base, self.device_xml_path), + "Cache-Control:max-age=": self.max_age + } + + data += "%s\r\n" % data_command + for data_key in list(data_dict.keys()): + data += "%s:%s\r\n" % (data_key, data_dict[data_key]) data += "\r\n" + self.ssdp_content = data return data.encode("utf-8") diff --git a/fHDHR/device/ssdp/rmg_ssdp.py b/fHDHR/device/ssdp/rmg_ssdp.py index 31d6466..3cf9a4a 100644 --- a/fHDHR/device/ssdp/rmg_ssdp.py +++ b/fHDHR/device/ssdp/rmg_ssdp.py @@ -2,43 +2,38 @@ class RMG_SSDP(): - def __init__(self, fhdhr, _broadcast_ip): + def __init__(self, fhdhr, broadcast_ip, max_age): self.fhdhr = fhdhr self.ssdp_content = None - self._broadcast_ip = _broadcast_ip - self.nt = 'urn:schemas-upnp-org:device-1-0' - self.usn = 'uuid:' + fhdhr.config.dict["main"]["uuid"] + '::' + self.nt - self.server = 'fHDHR/%s UPnP/1.0' % fhdhr.version - self.location = ('http://' + fhdhr.config.dict["fhdhr"]["discovery_address"] + ':' + - str(fhdhr.config.dict["fhdhr"]["port"]) + '/device.xml') - self.al = self.location - self.max_age = 1800 + self.broadcast_ip = broadcast_ip + self.device_xml_path = '/device.xml' + + self.max_age = max_age def get(self): if self.ssdp_content: return self.ssdp_content.encode("utf-8") - data = ( - "NOTIFY * HTTP/1.1\r\n" - "HOST:{}\r\n" - "NT:{}\r\n" - "NTS:ssdp:alive\r\n" - "USN:{}\r\n" - "SERVER:{}\r\n" - ).format( - self._broadcast_ip, - self.nt, - self.usn, - self.server - ) - if self.location is not None: - data += "LOCATION:{}\r\n".format(self.location) - if self.al is not None: - data += "AL:{}\r\n".format(self.al) - if self.max_age is not None: - data += "Cache-Control:max-age={}\r\n".format(self.max_age) + data = '' + data_command = "NOTIFY * HTTP/1.1" + + data_dict = { + "HOST": "%s:%s" % (self.broadcast_ip, 1900), + "NT": 'urn:schemas-upnp-org:device-1-0', + "NTS": "ssdp:alive", + "USN": 'uuid:%s::%s' % (self.fhdhr.config.dict["main"]["uuid"], 'urn:schemas-upnp-org:device-1-0'), + "SERVER": 'fHDHR/%s UPnP/1.0' % self.fhdhr.version, + "LOCATION": "%s%s" % (self.fhdhr.api.base, self.device_xml_path), + "AL": "%s%s" % (self.fhdhr.api.base, self.device_xml_path), + "Cache-Control:max-age=": self.max_age + } + + data += "%s\r\n" % data_command + for data_key in list(data_dict.keys()): + data += "%s:%s\r\n" % (data_key, data_dict[data_key]) data += "\r\n" + self.ssdp_content = data return data.encode("utf-8") diff --git a/fHDHR/device/tuners/tuner.py b/fHDHR/device/tuners/tuner.py index 09c7421..d1aa593 100644 --- a/fHDHR/device/tuners/tuner.py +++ b/fHDHR/device/tuners/tuner.py @@ -18,13 +18,8 @@ class Tuner(): self.tuner_lock = threading.Lock() self.set_off_status() - if fhdhr.config.dict["fhdhr"]["address"] == "0.0.0.0": - self.location = ('http://127.0.0.1:%s' % str(fhdhr.config.dict["fhdhr"]["port"])) - else: - self.location = ('http://%s:%s' % (fhdhr.config.dict["fhdhr"]["address"], str(fhdhr.config.dict["fhdhr"]["port"]))) - - self.chanscan_url = "%s/api/channels?method=scan" % (self.location) - self.close_url = "%s/api/tuners?method=close&tuner=%s" % (self.location, str(self.number)) + self.chanscan_url = "%s/api/channels?method=scan" % (self.fhdhr.api.base) + self.close_url = "%s/api/tuners?method=close&tuner=%s" % (self.fhdhr.api.base, str(self.number)) def channel_scan(self): if self.tuner_lock.locked(): diff --git a/fHDHR_web/__init__.py b/fHDHR_web/__init__.py index 86b9742..7b01fdb 100644 --- a/fHDHR_web/__init__.py +++ b/fHDHR_web/__init__.py @@ -89,10 +89,11 @@ class fHDHR_HTTP_Server(): self.app.add_url_rule(endpoint, endpoint_name, handler, methods=methods) def run(self): - self.http = WSGIServer(( - self.fhdhr.config.dict["fhdhr"]["address"], - int(self.fhdhr.config.dict["fhdhr"]["port"]) - ), self.app.wsgi_app, log=self.fhdhr.logger) + + self.http = WSGIServer(self.fhdhr.api.address_tuple, + self.app.wsgi_app, + log=self.fhdhr.logger) + try: self.http.serve_forever() except KeyboardInterrupt: diff --git a/fHDHR_web/pages/cluster_html.py b/fHDHR_web/pages/cluster_html.py index 95fdb21..cc26a12 100644 --- a/fHDHR_web/pages/cluster_html.py +++ b/fHDHR_web/pages/cluster_html.py @@ -10,9 +10,9 @@ class Cluster_HTML(): self.fhdhr = fhdhr self.location_dict = { "name": self.fhdhr.config.dict["fhdhr"]["friendlyname"], - "location": self.fhdhr.device.cluster.location, + "location": self.fhdhr.api.base, "joined": "N/A", - "url_query": self.fhdhr.device.cluster.location_url + "url_query": self.fhdhr.api.base_quoted } def __call__(self, *args):