Beispiel #1
0
 def __init__(self, id=0, timeout=120, use_rtc_memory=True):
     self._timeout = timeout / 10
     self._counter = 0
     self._timer = machine.Timer(id)
     self._use_rtc_memory = use_rtc_memory
     self._has_filesystem = False
     self.init()
     asyncio.get_event_loop().create_task(self._resetCounter())
     if sys_vars.hasFilesystem():
         self._has_filesystem = True
         try:
             with open("watchdog.txt", "r") as f:
                 if f.read() == "True":
                     logging.getLogger("WDT").warn("Reset reason: Watchdog")
         except Exception as e:
             print(e)  # file probably just does not exist
         try:
             with open("watchdog.txt", "w") as f:
                 f.write("False")
         except Exception as e:
             logging.getLogger("WDT").error("Error saving to file: {!s}".format(e))
     elif use_rtc_memory and platform == "esp8266":
         rtc = machine.RTC()
         if rtc.memory() == b"WDT reset":
             logging.getLogger("WDT").critical("Reset reason: Watchdog")
         rtc.memory(b"")
Beispiel #2
0
 async def _buildComponents(self, topic=None, msg=None, retain=None):
     log.debug("Building components", local_only=True)
     loop = asyncio.get_event_loop()
     await self.unsubscribe("{!s}/login/".format(self.mqtt_home) + self.id)
     if type(msg) != dict:
         log.critical("Received config is no dict")
         msg = None
     if msg is None:
         log.error("No configuration received, falling back to last saved config")
         loop.create_task(config.loadComponentsFile())
     else:
         log.info("received config: {!s}".format(msg), local_only=True)
         # saving components
         config.saveComponentsFile(msg)
         if platform == "esp8266":
             # on esp8266 components are split in small files and loaded after each other
             # to keep RAM requirements low, only if filesystem is enabled
             if sys_vars.hasFilesystem():
                 loop.create_task(config.loadComponentsFile())
             else:
                 loop.create_task(config.registerComponentsAsync(msg))
         else:
             # on esp32 components are registered directly but async to let logs run between registrations
             loop.create_task(config.registerComponentsAsync(msg))
     self.__receive_config = None
Beispiel #3
0
 async def _receiveConfig(self):
     self.__receive_config = None
     while True:
         gc.collect()
         _log.debug("RAM before receiveConfig import: {!s}".format(
             gc.mem_free()),
                    local_only=True)
         import pysmartnode.networking.mqtt_receive_config
         gc.collect()
         _log.debug("RAM after receiveConfig import: {!s}".format(
             gc.mem_free()),
                    local_only=True)
         result = await pysmartnode.networking.mqtt_receive_config.requestConfig(
             config, self, _log)
         if result is False:
             _log.info("Using local components.json/py", local_only=True)
             gc.collect()
             _log.debug("RAM before receiveConfig deletion: {!s}".format(
                 gc.mem_free()),
                        local_only=True)
             del pysmartnode.networking.mqtt_receive_config
             del sys.modules["pysmartnode.networking.mqtt_receive_config"]
             gc.collect()
             _log.debug("RAM after receiveConfig deletion: {!s}".format(
                 gc.mem_free()),
                        local_only=True)
             local_works = await config._loadComponentsFile()
             if local_works is True:
                 return True
         else:
             gc.collect()
             _log.debug("RAM before receiveConfig deletion: {!s}".format(
                 gc.mem_free()),
                        local_only=True)
             del pysmartnode.networking.mqtt_receive_config
             del sys.modules["pysmartnode.networking.mqtt_receive_config"]
             gc.collect()
             _log.debug("RAM after receiveConfig deletion: {!s}".format(
                 gc.mem_free()),
                        local_only=True)
             result = ujson.loads(result)
             loop = asyncio.get_event_loop()
             if platform == "esp8266":
                 # on esp8266 components are split in small files and loaded after each other
                 # to keep RAM requirements low, only if filesystem is enabled
                 if sys_vars.hasFilesystem():
                     loop.create_task(config._loadComponentsFile())
                 else:
                     loop.create_task(
                         config._registerComponentsAsync(result))
             else:
                 # on esp32 components are registered directly but async to let logs run between registrations
                 loop.create_task(config._registerComponentsAsync(result))
             return True
         await asyncio.sleep(
             60
         )  # if connection not stable or broker unreachable, try again in 60s
Beispiel #4
0
 def _wdt(self, t):
     self._counter += self._timeout
     if self._counter >= self._timeout * 10:
         if sys_vars.hasFilesystem():
             try:
                 with open("watchdog.txt", "w") as f:
                     f.write("True")
             except Exception as e:
                 print("Error saving to file: {!s}".format(e))
         machine.reset()
async def loadComponentsFile(_log, registerComponentsAsync):
    if not sys_vars.hasFilesystem():
        comps = _importComponents(_log)
        if comps is False:
            _log.critical(
                "Can't load components file as filesystem is unavailable")
            return False
        return comps
    try:
        f = open("components.json", "r")
        components_found = True
    except OSError:
        components_found = False
    if components_found is False:
        try:
            f = open("_order.json", "r")
        except Exception as e:
            # if loading configuration jsons fails, try to import components.py
            comps = _importComponents(_log)
            if comps is False:
                _log.critical("_order.json does not exist, {!s}".format(e))
                return False
            else:
                return comps
        order = ujson.loads(f.read())
        f.close()
        gc.collect()
        for component in order:
            tmp = {"_order": [component]}
            try:
                f = open("components/{!s}.json".format(component), "r")
                tmp[component] = ujson.loads(f.read())
                f.close()
                await registerComponentsAsync(tmp)
            except Exception as e:
                _log.error("Error loading component file {!s}, {!s}".format(
                    component, e))
            gc.collect()
            if platform == "esp8266":
                await asyncio.sleep(1)
                # gives time to get retained topic and settle ram, important on esp8266
            else:
                await asyncio.sleep_ms(100)
            gc.collect()
        return True
    else:
        c = f.read()
        f.close()
        try:
            c = ujson.loads(c)
            gc.collect()
            return c
        except Exception as e:
            _log.critical("components.json parsing error {!s}".format(e))
            return False
Beispiel #6
0
 def __init__(self, receive_config=False, allow_wildcards=True):
     """
     receive_config: False, if true tries to get the configuration of components
         from a server connected to the mqtt broker
     allow_wildcards: True, if false no subscriptions ending with "/#" are allowed;
         this also saves RAM as the module "subscription" is used as a backend 
         to store subscriptions instead of the module "tree" which is bigger
     """
     if platform == "esp8266" and sys_vars.hasFilesystem():
         """ esp8266 has very limited RAM so choosing a module that allows wildcards
         but writes subscribed topics to a file if filesystem is enabled, else uses Tree.
         - less feature and less general
         + specifically made for mqtt and esp8266
         - makes it a lot slower (~30ms checking a subscription, ~120ms saving one)
         + saves at least 1kB with a few subscriptions
         """
         from pysmartnode.utils.subscriptionHandlers.subscribe_file import SubscriptionHandler
         self._subscriptions = SubscriptionHandler()
     else:
         """ 
         esp32 has a lot of RAM but if wildcards are not needed then
         the subscription module is faster and saves ram but does not support wildcards.
         For wildcard support the module tree is used.
         Also used for esp8266 with no filesystem (which saves ~6kB)
         """
         if allow_wildcards:
             from pysmartnode.utils.subscriptionHandlers.tree import Tree
             gc.collect()
             self._subscriptions = Tree(config.MQTT_HOME, ["Functions"])
         else:
             from pysmartnode.utils.subscriptionHandlers.subscription import SubscriptionHandler
             gc.collect()
             self._subscriptions = SubscriptionHandler(["Functions"])
     self._allow_wildcards = allow_wildcards
     self.payload_on = ("ON", True, "True")
     self.payload_off = ("OFF", False, "False")
     self._retained = []
     self.id = config.id
     self.mqtt_home = config.MQTT_HOME
     super().__init__(server=config.MQTT_HOST,
                      port=1883,
                      user=config.MQTT_USER,
                      password=config.MQTT_PASSWORD,
                      keepalive=config.MQTT_KEEPALIVE,
                      subs_cb=self._execute_sync,
                      wifi_coro=self._wifiChanged,
                      connect_coro=self._connected,
                      will=(self.getRealTopic(self.getDeviceTopic("status")), "OFFLINE", True, 1),
                      clean=False,
                      ssid=config.WIFI_SSID,
                      wifi_pw=config.WIFI_PASSPHRASE)
     asyncio.get_event_loop().create_task(self.connect())
     self.__receive_config = receive_config
Beispiel #7
0
 def __init__(self, id=0, timeout=120):
     self._timeout = timeout / 10
     self._counter = 0
     self._timer = machine.Timer(id)
     self.init()
     asyncio.get_event_loop().create_task(self._resetCounter())
     if sys_vars.hasFilesystem():
         try:
             with open("watchdog.txt", "r") as f:
                 if f.read() == "True":
                     log.warn("Reset reason: Watchdog")
         except Exception as e:
             print(e)  # file probably just does not exist
         try:
             with open("watchdog.txt", "w") as f:
                 f.write("False")
         except Exception as e:
             log.error("Error saving to file: {!s}".format(e))
Beispiel #8
0
def _saveComponentsFile(msg):
    from pysmartnode.utils import sys_vars
    from sys import platform
    import os
    import gc
    if not sys_vars.hasFilesystem():
        _log.debug("Not saving components as filesystem is unavailable",
                   local_only=True)
        return
    if platform == "esp8266":
        tmp = ujson.dumps(msg["_order"])
        f = open("_order.json", "w")
        f.write(tmp)
        f.close()
        del tmp
        try:
            os.mkdir("components")
        except Exception as e:
            # probably already there
            f = os.listdir("components")
            for file in f:
                os.remove("components/" + file)
            del f
            gc.collect()
        for component in msg:
            if component != "_order":
                try:
                    f = open("components/{!s}.json".format(component), "w")
                    f.write(ujson.dumps(msg[component]))
                    f.close()
                except Exception as e:
                    _log.error("Can't save component {!s}, {!s}".format(
                        component, e))
        try:
            os.remove("components.json")
        except Exception as e:
            pass
    else:
        tmp = ujson.dumps(msg)
        f = open("components.json", "w")
        f.write(tmp)
        f.close()