def rtc_ntp_sync(TZ=0, timeout_s = 30): from machine import RTC print("sync rtc via ntp, TZ=", TZ) rtc = RTC() print("synced?", rtc.synced()) rtc.ntp_sync('nl.pool.ntp.org') print("synced?", rtc.synced()) #time.sleep_ms(750) time.timezone(TZ * 3600) timeout_ms = 1000 * timeout_s for i in range(0, timeout_ms): if rtc.synced(): print("rtc is synced after", i/1000, "s") # if rtc.now()[0] == 1970: # print() break if i % 100 == 0: print(".", end="") time.sleep_ms(1) if not rtc.synced(): raise Exception("RTC did not sync in", timeout_ms/1000, "s") print("rtc.now", rtc.now()) print("time.gmtime", time.gmtime()) print("time.localtime", time.localtime()) print("gmt ", end=" ") pretty_gmt() print("local", end=" ") pretty_local()
def rtc_init(): global rtc_synced rtc = RTC() rtc.ntp_sync('pool.ntp.org', update_period=15) print('Waiting for RTC/NTP sync...') chrono = Timer.Chrono() chrono.start() while not rtc.synced(): # wait for 30 seconds, then give up and try manual NTP sync if chrono.read() > 30: print('Sync timed out after %s seconds...' % chrono.read()) rtc.ntp_sync(None) break time.sleep(1) if rtc.synced(): print('RTC Set from NTP daemon to UTC:', rtc.now()) rtc_synced = True else: print('Fetching time from NTP server manually...') try: NTP_QUERY = bytearray(48) NTP_QUERY[0] = 0x1b addr = socket.getaddrinfo('pool.ntp.org', 123)[0][-1] s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.settimeout(3) s.sendto(NTP_QUERY, addr) msg = s.recv(48) s.close() # 70 years difference between NTP and Pycom epoch val = struct.unpack("!I", msg[40:44])[0] - 2208988800 tm = time.localtime(val) rtc.init(tm) rtc_synced = True gc.collect() except socket.timeout: print('Timed out while fetching time from remote server.') if not rtc.synced() and rtc_synced: print('RTC Set from manual NTP call to UTC:', rtc.now()) # adjust timezone if rtc_synced: # UTC-7/MST for testing time.timezone(-7*60*60) print('RTC adjusted from UTC to local timezone:', time.localtime()) else: print('Unable to set RTC', rtc.now()) print('Resetting NTP sync to 15 minutes') rtc.ntp_sync('pool.ntp.org', 60*15)
def do_deep_sleep(floater): print("Water level is OK. Going to sleep..") # Ref https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/wiki/rtc rtc = RTC() rtc.ntp_sync(server="hr.pool.ntp.org", tz="CET-1CEST") rtc.synced() rtc.wake_on_ext0(floater, 0) # ESP32 power reduction for battery powered # https://forum.micropython.org/viewtopic.php?t=3900 deepsleep(0)
def start_rtc(): """ Start and sync RTC. Requires WLAN. """ rtc = RTC() rtc.ntp_sync(server="pool.ntp.org") for _ in range(100): if rtc.synced(): break sleep_ms(100) if rtc.synced(): pass # print(strftime("%c", localtime())) else: print("Unable to get ntp time")
def sync_rtc(rtcserver): #a.st1.ntp.br #b.st1.ntp.br #c.st1.ntp.br #d.st1.ntp.br #a.ntp.br #b.ntp.br #c.ntp.br #gps.ntp.br #pool.ntp.org from machine import RTC from time import sleep print("Syncing RTC...") rtc = RTC() print(rtc.now()) rtc.ntp_sync(rtcserver) sleep(1) while not rtc.synced(): print("Still syncing RTC...") rtc.ntp_sync(rtcserver) sleep(5) print(rtc.now()) print("RTC Synchronized.\n")
def setRTCLocalTime(): rtc = RTC() print("Time before sync: ", rtc.now()) rtc.ntp_sync("pool.ntp.org") while not rtc.synced(): utime.sleep(1) print("Waiting for NTP server...") print('\nTime after sync: ', rtc.now())
def connect(): wlan = network.WLAN(mode=network.WLAN.STA) wlan.connect('VM8707621', auth=(network.WLAN.WPA2, 'sm7zkSspWsmq')) while not wlan.isconnected(): time.sleep_ms(50) print(wlan.ifconfig()) rtc = RTC() rtc.ntp_sync("pool.ntp.org") while not rtc.synced(): time.sleep_ms(50) print(rtc.now())
def ntp_sync(self): if self.online() and self.settings.get('timezone'): timezone = '<' if self.settings['timezone'] > 0: timezone += '+' if -10 < self.settings['timezone'] < 10: timezone += '0' timezone += str(self.settings['timezone']) + '>' + str( -self.settings['timezone']) rtc = RTC() rtc.ntp_sync(server='pool.ntp.org', tz=timezone, update_period=3600) if not rtc.synced(): print(' waiting for time sync...', end='') utime.sleep(0.5) while not rtc.synced(): print('.', end='') utime.sleep(0.5) print('') print('Time:', self.post_tstamp()) if self.modules.get('rtc'): self.modules['rtc'].save_time()
def print_debug_local(level, msg): """ Print log messages. log messages will be stored in the device so the user can access that using FTP or Flash OTA. """ if DEBUG is not None and level <= DEBUG: print_debug(0, 'adding local log') rtc = RTC() if not rtc.synced(): rtc.ntp_sync("pool.ntp.org") while not rtc.synced(): pass current_year, current_month, current_day, current_hour, current_minute, current_second, current_microsecond, current_tzinfo = rtc.now() # noqa msg = '\n {}-{}-{} {}:{}:{} (GMT+{}) >>> {}'.format( current_day, current_month, current_year, current_hour, current_minute, current_second, timezone(), msg ) try: fsize = os.stat('logs.log') if fsize.st_size > 1000000: # logs are bigger than 1 MB os.remove("logs.log") except Exception: pass log_file = open('logs.log', 'a+') log_file.write(msg) log_file.close()
def sync_rtc(interval=11, max_count=100): print("Try to synchronize network time") rtc = RTC() rtc.ntp_sync('ntp.nict.jp', tz='JST-9') count = 0 while count < max_count: if rtc.synced(): message = 'RTC synced. {}'.format(utime.localtime()) print(message) lcd.println(message, color=lcd.GREEN) break utime.sleep_ms(interval) #print('.') count += 1
lcd.clear() # Init GPS lcd.print('UART:Initializing\n', 0, 0) gps_s = UART(2, tx=17, rx=16, baudrate=9600, timeout=200, buffer_size=256, lineend='\r\n') # micropyGPS.MicropyGPS.supported_sentences.update({'GNGSA': micropyGPS.MicropyGPS.gpgsa}) gps = micropyGPS.MicropyGPS(9, 'dd') lcd.print('UART:Initialized\n') # Init RTC lcd.print('RTC:Initializing\n') rtc = RTC() rtc.ntp_sync(server='hr.pool.ntp.org', tz='CET-1CEST') lcd.print('RTC:Initialize status %s\n' % rtc.synced()) # Mount SD result = uos.mountsd() lcd.print('SDCard:Mount result %s\n' % result) lcd.print('SDCard:listdir %s\n' % uos.listdir('/sd')) def watchGPS(): lcd.print('GPS:Start loop\n') n = 0 tm_last = 0 satellites = dict() satellites_used = dict()
class HttpNotifier(): def connection_timer_handler(self, alarm): if not self._wlan.isconnected(): print('failed to connect to {}, restarting...'.format(wifi_config['ssid'])) reset() def sync_timer_handler(self, alarm): if not self._rtc.synced(): print('failed to sync time with ntp, restarting...') reset() def __init__(self, thng_id, api_key): self._thng_id = thng_id self._http_headers = {'Content-Type': 'application/json', 'Authorization': api_key} self._rtc = RTC() self._wlan = WLAN(mode=WLAN.STA) nets = self._wlan.scan() print('WLAN: scanned networks: {}'.format([net.ssid for net in nets])) for net in nets: if net.ssid == wifi_config['ssid']: print('WLAN: connecting to {}...'.format(net.ssid)) self._wlan.connect(wifi_config['ssid'], auth=( net.sec, wifi_config['passphrase']), timeout=30000) Timer.Alarm(self.connection_timer_handler, 35, periodic=False) while not self._wlan.isconnected(): idle() # save power while waiting print('WLAN: connection to {} succeeded!'.format(wifi_config['ssid'])) print('ifconfig: {}'.format(self._wlan.ifconfig())) self._send_props([{'key': 'in_use', 'value': False}]) Timer.Alarm(self.sync_timer_handler, 30, periodic=False) while not self._rtc.synced(): self._rtc.ntp_sync('pool.ntp.org', update_period=3600) time.sleep(1) print("time synced: {}".format(self._rtc.now())) # seems like we are still not connected, # setup wifi network does not exist ??? if not self._wlan.isconnected(): print('failed to connect or specified network does not exist') time.sleep(20) reset() # provision.enter_provisioning_mode() def _send(self, method, url, json): print('REQUEST: {}: {}'.format(method, json)) try: resp = requests.request(method=method, url=url, json=json, headers=self._http_headers) except OSError as e: print('RESPONSE: failed to perform request: {}'.format(e)) if not self._wlan.isconnected(): print('wifi connection lost, restarting...') time.sleep(3) reset() else: print('RESPONSE: {}...'.format(str(resp.json())[:100])) gc_collect() def _send_props(self, data): self._send(method='PUT', url='https://api.evrythng.com/thngs/{}/properties'.format(self._thng_id), json=data) def _send_actions(self, data): for action in data: self._send(method='POST', url='https://api.evrythng.com/thngs/{}/actions/all'.format(self._thng_id), json=action) def handle_notifications(self, notifications): properties = [] actions = [] for n in notifications: if n.type == NotificationQueue.VIBRATION_STARTED: properties.append({'key': 'in_use', 'value': True, 'timestamp': n.timestamp}) actions.append({'type': '_appliance_started', 'timestamp': n.timestamp}) elif n.type == NotificationQueue.VIBRATION_STOPPED: properties.extend([{'key': 'in_use', 'value': False, 'timestamp': n.timestamp}, {'key': 'last_use', 'value': n.data, 'timestamp': n.timestamp}]) actions.append({'type': '_appliance_stopped', 'timestamp': n.timestamp}) elif n.type == NotificationQueue.UPTIME: properties.append({'key': 'uptime', 'value': n.data, 'timestamp': n.timestamp}) elif n.type == NotificationQueue.AMBIENT: properties.extend([ {'key': 'temperature', 'value': n.data[0], 'timestamp': n.timestamp}, {'key': 'humidity', 'value': n.data[1], 'timestamp': n.timestamp}, {'key': 'pressure', 'value': n.data[2], 'timestamp': n.timestamp}, {'key': 'battery_voltage', 'value': n.data[3], 'timestamp': n.timestamp} ]) elif n.type == NotificationQueue.VERSION: properties.append({'key': 'version', 'value': n.data, 'timestamp': n.timestamp}) elif n.type == NotificationQueue.MAGNITUDE: if not len(n.data): return properties.append({'key': 'magnitude', 'value': n.data, 'timestamp': n.timestamp}) else: print('unsupported event {}'.format(n.type)) if actions: self._send_actions(actions) if properties: self._send_props(properties)
class LoraSense: """ Class object that receives optional pin arguments for the SDA-pin (Serial Data), the SCL-pin (Serial Clock) and the pin for the photometry module. The defaults are SDA = Pin3, SCL = Pin4, Phot = Pin20 on the Pycom Extension Board v3.1. """ def __init__(self, sda="P3", scl="P4", als="P20", frequency=1, mode=0, debug=0): if not (mode == 0 or mode == 1): self.__exitError("Please initialize this module in either mode 0 or mode 1.") self.mode = mode self.rtc = RTC() self.debug = debug self.wlan = WLAN(mode=WLAN.STA) self.UDPactive = False self.loraActive = False if (mode == 0): adc = ADC() self.bme280 = bme280.BME280(i2c=I2C(pins=(sda, scl))) self.l_pin = adc.channel(pin=als) self.frequency = frequency """ This procedure sets up the LoRa-connection. """ def setupLoRa(self, mode=LoRa.LORA, region=LoRa.EU868, tx_power=14, sf=7): self.lora = LoRa(mode=mode, region=region) self.lora.init(mode=mode, tx_power=tx_power, sf=sf) self.lorasocket = socket.socket(socket.AF_LORA, socket.SOCK_RAW) self.lorasocket.setblocking(False) self.loraActive = True def setupWLAN(self, ssid, pw, timeout=60): self.wlan.connect(ssid=ssid, auth=(WLAN.WPA2, pw)) counter = 0 print("Connecting to WLAN", end = '') while not self.wlan.isconnected(): counter = counter + 1 if (counter == timeout): print("Unable to connect (timed out).") return time.sleep(1) print(".", end = '') if self.wlan.isconnected(): print(" Connected!") counter = 0 self.rtc.ntp_sync("0.ch.pool.ntp.org") print("Connecting to NTP server ", end = '') while not self.rtc.synced(): counter = counter + 1 if (counter == timeout): print("Unable to connect (timed out).") return print(".", end = '') time.sleep(1) print(" Completed!") def setupUDP(self, IP, port): self.__debug("DEBUG: STARTING UDP -> IP: {} Port: {}$".format(IP, port)) if not self.wlan.isconnected(): self.__exitError("Please establish a WLAN connection first.") if (self.mode == 0): print("UDP can only be set up in mode 1.") elif (self.mode == 1): self.UDPaddress = (IP, port) print("Establishing a UDP connection.. to {}".format(self.UDPaddress[0])) self.UDPsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.UDPsocket.connect(self.UDPaddress) self.UDPsocket.sendto("Establish".encode("utf-8"), self.UDPaddress) self.UDPactive = True else: print("LoRa mode must be either 0 or 1.s") def setSendFreq(self, sec): self.frequency = sec def startCommunication(self): if self.mode == 0: self.__commInMode0() elif self.mode == 1: self.__commInMode1() def __createSocketList(self): if (self.loraActive and self.UDPactive): return [self.lorasocket, self.UDPsocket] elif (self.loraActive and not self.UDPactive): return [self.lorasocket] elif (not self.loraActive and self.UDPactive): return [self.UDPsocket] else: self.__exitError("Please establish a LoRa or a UDP connection before starting communication.") def __commInMode0(self): self.sockets = self.__createSocketList() self.__debug("Communication in mode 0 initiated. Sockets = {}".format(self.sockets)) while True: readIn, writeOut, excep = select.select(self.sockets, self.sockets, []) for insocket in readIn: if insocket == self.lorasocket: info = insocket.recv(52) print(info) self.__processInfo(info) elif insocket == self.UDPsocket: info = insocket.recv(52) print(info) insocket.send(info) for outsocket in writeOut: if outsocket == self.lorasocket: print(self.__getValues()) self.lorasocket.send(self.__getValues()) time.sleep(self.frequency) def __commInMode1(self): self.sockets = self.__createSocketList() self.__debug("Communication in mode 1 initiated. Sockets = {}".format(self.sockets)) while True: readIn, writeOut, excep = select.select(self.sockets, self.sockets, []) for insocket in readIn: if insocket == self.lorasocket: info = insocket.recv(52) insocket.send(info) self.__sendUDP(info) elif insocket == self.UDPsocket: info = insocket.recv(52) self.lorasocket.send(info) def __getTimeStamp(self, offset_sec=0, offset_min=0, offset_hour=0, offset_day=0, offset_month=0, offset_year=0): self.rtc.ntp_sync("0.ch.pool.ntp.org") time = self.rtc.now() seconds = self.__zfill(str(time[5] + offset_sec),2) minutes = self.__zfill(str(time[4] + offset_min),2) hour = self.__zfill(time[3] + offset_hour,2) day = time[2] + offset_day month = time[1] + offset_month year = time[0] - 2000 + offset_year return "{}/{}/{}|{}:{}:{}|".format(day, month, year, hour, minutes, seconds) def __zfill(self, s, width): return '{:0>{w}}'.format(s, w=width) def __getValues(self): t, p, h = self.bme280.values li = self.l_pin() msg = '{:.02f}|{:.02f}|{:.02f}|{:.02f}'.format(t, p, h, li / 4095 * 100) if self.wlan.isconnected(): if (self.debug == 1): print(self.__getTimeStamp(offset_hour=2) + msg) return self.__getTimeStamp(offset_hour=2) + msg else: if (self.debug == 1): print(msg) return msg def __sendLoRa(self): self.__getTimeStamp(offset_hour=2) self.lorasocket.send(self.__getValues()) def __sendInfo(self): while True: self.__sendLoRa() time.sleep(self.frequency) def __getInfo(self): try: while True: info = self.lorasocket.recv(52) if self.UDPactive: self.__sendUDP(info) if self.debug == 1: print(info) time.sleep(1) except UnicodeError: pass def __processInfo(self, info): try: info = info.decode("utf-8").split("|") if (info[0] == "freq"): self.frequency = int(info[1]) print("New frequency set: {}".format(int(info[1]))) except UnicodeError: pass def showIP(self): if self.wlan.isconnected(): print("IP: {}".format(self.wlan.ifconfig()[0])) else: print("You need to establish an internet connection first.") def __sendUDP(self, msg): self.UDPsocket.sendto(msg, self.UDPaddress) def __getUDP(self): while True: data, ip = self.UDPsocket.recvfrom(1024) if data: print("Data: " + data.decode()) def __exitError(self, str): print('\033[91m' + "Error: " + str + '\x1b[0m') sys.exit() def __debug(self, str): if self.debug == 1: print('\033[93m' + "Debug: " + str + '\x1b[0m')
class udatetime: def __init__(self): self.__datetime = Datetime() self.__timetuple = () self.__seconds = 0 self.__rtc = RTC() self.__rtc.ntp_sync("pool.ntp.org") # sync to UTC time while not self.__rtc.synced(): sleep(1) # get_current_time() will be the core method to be called to get latest datetime # and update the values of corresponding attributes def get_current_time(self): self.__timetuple = self.__rtc.now() self.__datetime.year, self.__datetime.month, self.__datetime.day, self.__datetime.hour, self.__datetime.minute, self.__datetime.second, *args = self.__timetuple def utcnow(self) -> udatetime: self.get_current_time() return self def utc_seconds(self) -> int: self.get_current_time() self.__seconds = utime.mktime(self.__timetuple) return self.__seconds def year(self) -> int: return self.__datetime.year def month(self) -> int: return self.__datetime.month def day(self) -> int: return self.__datetime.day def hour(self) -> int: return self.__datetime.hour def minute(self) -> int: return self.__datetime.minute def second(self) -> int: return self.__datetime.second def strftime(self, dt_format: str) -> str: dt_map = { "%Y": "{:4}".format(self.__datetime.year), "%m": "{:02}".format(self.__datetime.month), "%d": "{:02}".format(self.__datetime.day), "%H": "{:02}".format(self.__datetime.hour), "%M": "{:02}".format(self.__datetime.minute), "%S": "{:02}".format(self.__datetime.second) } for key, value in dt_map.items(): if key in dt_format: dt_format = dt_format.replace(key, value) return dt_format def __str__(self) -> str: return "{:4}-{:02}-{:02}T{:02}:{:02}:{:02}Z".format( self.__datetime.year, self.__datetime.month, self.__datetime.day, self.__datetime.hour, self.__datetime.minute, self.__datetime.second)
class SenseLink: """ Class object that receives optional pin arguments for the SDA-pin (Serial Data), the SCL-pin (Serial Clock) and the pin for the photometry module. The defaults are SDA = Pin3, SCL = Pin4, Phot = Pin20 on the Pycom Extension Board v3.1. """ def __init__(self, sda="P3", scl="P4", als="P20", ssid="", pw="", frequency=5, debug=0, feed_layer=None): self.feed_layer = feed_layer self.fid = self.feed_layer.get_sensor_feed_fid() self.cfid = self.feed_layer.get_control_feed_fid() self.rtc = RTC() self.debug = debug self.lastsent = 0 self.switch = True self.wlan = WLAN(mode=WLAN.STA) self.connectWlan(ssid=ssid, pw=pw) self.subscribe_state = self.feed_layer.subscribe_control_feed( self.callback) self.frequency = frequency self.__debug("Sensor Feed ID is: " + str(self.fid)) self.__debug("Control Feed ID is: " + str(self.cfid)) try: self.bme280 = bme280.BME280(i2c=I2C(pins=(sda, scl))) except: self.__exitError( "BME280 not recognized. Please check the connections.", loop=True, col=1) self.l_pin = ADC().channel(pin=als) def getFid(self): return self.fid def getCfid(self): return self.cfid def switchState(self): return self.switch def callback(self, event): self.__debug("Event received: {}".format(event)) self.setFrequency(int(event)) def setFrequency(self, val): self.__debug("Frequency changed to {}".format(val)) self.frequency = val def getFrequency(self): return self.frequency def createEvent(self): self.vals = self.__getValues() event = "['{}', '{:.2f}', '{:.2f}', '{:.2f}', '{:.2f}']".format( self.vals[0], self.vals[1], self.vals[2], self.vals[3], self.vals[4]) self.__debug("Creating event: " + event) return event def connectWlan(self, ssid, pw, timeout=5): self.wlan.connect(ssid=ssid, auth=(WLAN.WPA2, pw)) counter = 0 self.__debug("Connecting to WLAN", newline=False) while not self.wlan.isconnected(): counter = counter + 1 if (counter == timeout): self.__exitError("Unable to connect (timed out).", loop=True, col=0) return time.sleep(1) self.__debug(".", newline=False) if self.wlan.isconnected(): self.__debug(" Connected! ", newline=False) counter = 0 self.rtc.ntp_sync("0.ch.pool.ntp.org") self.__debug("Connecting to NTP server ", newline=False) while not self.rtc.synced(): counter = counter + 1 if (counter == timeout): self.__exitError("Unable to connect (timed out).", loop=True, col=0) return self.__debug(".", newline=False) time.sleep(1) self.__debug(" Completed!", newline=False) self.switch = False self.__debug("Connection established and time data received.") def __getTimeStamp(self, offset_sec=0, offset_min=0, offset_hour=0, offset_day=0, offset_month=0, offset_year=0): if self.wlan.isconnected(): self.rtc.ntp_sync("0.ch.pool.ntp.org") time = self.rtc.now() seconds = self.__zfill(str(time[5] + offset_sec), 2) minutes = self.__zfill(str(time[4] + offset_min), 2) hour = self.__zfill(time[3] + offset_hour, 2) day = self.__zfill(time[2] + offset_day, 2) month = self.__zfill(time[1] + offset_month, 2) year = time[0] - 2000 + offset_year return "{}/{}/{} {}:{}:{}".format(day, month, year, hour, minutes, seconds) else: return "notime" def __zfill(self, s, width): return '{:0>{w}}'.format(s, w=width) def updateInfo(self): while True: self.__debug(self.__getTimeStamp() + " Switch state: {}".format(self.switch)) self.currentpack = self.__getValues() time.sleep(1) def __getValues(self): try: t, p, h = self.bme280.values li = self.l_pin() return self.__getTimeStamp(offset_hour=2), t, p, h, li / 4095 * 100 except: self.__exitError( "BME280 not recognized. Please check the connections.", loop=True) def __exitError(self, str, col, loop=False): print('\033[91m' + "Error: " + str + '\x1b[0m') pycom.heartbeat(False) if col == 0: pycom.rgbled(0x7f7f00) elif col == 1: pycom.rgbled(0x7f0000) if loop: while True: pass else: sys.exit() def __debug(self, str, newline=True): if newline: print('\033[93m' + "SenseLink | Debug: " + str + '\x1b[0m') else: print('\033[93m' + str + '\x1b[0m', end='')
import machine import config import time from machine import RTC from network import WLAN rtc = RTC() # Real Time Clock wlan = WLAN() # get current object, without changing the mode if machine.reset_cause() != machine.SOFT_RESET: wlan.init(mode=WLAN.STA) # configuration below MUST match your home router settings!! if not config.DHCP: wlan.ifconfig(config=(IP_ADDR, IP_MASK, IP_GATE, IP_DNS)) if not wlan.isconnected(): # change the line below to match your network ssid, security and password wlan.connect(config.WIFI_SSID, auth=(WLAN.WPA2, config.WIFI_PASS), timeout=5000) print('Connected to WiFi router on IP:', wlan.ifconfig()[0]) while not wlan.isconnected(): machine.idle() # save power while waiting while not rtc.synced(): rtc.ntp_sync(config.NTP) print('Trying to sync time to %s!' % config.NTP) time.sleep(1) pass
if floater.value() == 0: print("Water level warning!") if wifi(settings.WIFI_SSID, settings.WIFI_PWD): utime.sleep(2) print("Sending SMS") try: response = urequests.post(settings.SERIVET_URL, data=ujson.dumps(data), headers=headers) except: print("try again") response = urequests.post(settings.SERIVET_URL, data=ujson.dumps(data), headers=headers) print(response.json()) else: print("Failed to connect to WiFi") else: print("Water level is OK. Going to sleep..") # https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/wiki/rtc rtc = RTC() rtc.ntp_sync(server="hr.pool.ntp.org", tz="CET-1CEST") rtc.synced() rtc.wake_on_ext0(floater, 0) # https://forum.micropython.org/viewtopic.php?t=3900 deepsleep(0)
class Monitor(object): def __init__(self, solar_topic, grid_topic, mqtt_broker, wifi_credentials, graph_interval_s=60, update_interval_ms=1000): self._solar_topic = solar_topic self._grid_topic = grid_topic self._mqtt_broker = mqtt_broker self._wifi_credentials = wifi_credentials self._graph_interval = graph_interval_s self._update_interval = update_interval_ms self._graph_window = Monitor._shorten(self._graph_interval * 320) self._tft = None self._wlan = None self._mqtt = None self._battery = IP5306(I2C(scl=Pin(22), sda=Pin(21))) self._timer = Timer(0) self._rtc = RTC() self._button_a = ButtonA(callback=self._button_a_pressed) self._button_c = ButtonC(callback=self._button_c_pressed) self._solar = None self._usage = None self._grid = None self._importing = None self._prev_importing = None self._solar_avg_buffer = [] self._grid_avg_buffer = [] self._usage_buffer = [] self._solar_buffer = [] self._last_update = (0, 0, 0, 0, 0, 0) self._data_counter = 0 self._buffer_updated = False self._realtime_updated = False self._last_value_added = None self._menu_horizontal_pointer = 0 self._blank_menu = False self._log('Initializing TFT...') self._tft = display.TFT() self._tft.init(self._tft.M5STACK, width=240, height=320, rst_pin=33, backl_pin=32, miso=19, mosi=23, clk=18, cs=14, dc=27, bgr=True, backl_on=1) self._tft.tft_writecmd(0x21) # Invert colors self._tft.clear() self._tft.font(self._tft.FONT_Default) self._tft.text(0, 0, 'USAGE', self._tft.DARKGREY) self._tft.text(self._tft.CENTER, 0, 'IMPORTING', self._tft.DARKGREY) self._tft.text(self._tft.RIGHT, 0, 'SOLAR', self._tft.DARKGREY) self._tft.text(0, 14, 'Loading...', self._tft.DARKGREY) self._log('Initializing TFT... Done') def init(self): """ Init logic; connect to wifi, connect to MQTT and setup RTC/NTP """ self._log('Connecting to wifi ({0})... '.format( self._wifi_credentials[0]), tft=True) self._wlan = network.WLAN(network.STA_IF) self._wlan.active(True) self._wlan.connect(*self._wifi_credentials) safety = 10 while not self._wlan.isconnected() and safety > 0: # Wait for the wifi to connect, max 10s time.sleep(1) safety -= 1 self._log('Connecting to wifi ({0})... {1}'.format( self._wifi_credentials[0], 'Done' if safety else 'Fail')) self._log('Connecting to MQTT...', tft=True) if self._mqtt is not None: self._mqtt.unsubscribe('emon/#') self._mqtt = network.mqtt('emon', self._mqtt_broker, user='******', password='******', data_cb=self._process_data) self._mqtt.start() safety = 5 while self._mqtt.status()[0] != 2 and safety > 0: # Wait for MQTT connection, max 5s time.sleep(1) safety -= 1 self._mqtt.subscribe('emon/#') self._log( 'Connecting to MQTT... {0}'.format('Done' if safety else 'Fail')) self._log('Sync NTP...', tft=True) self._rtc.ntp_sync(server='be.pool.ntp.org', tz='CET-1CEST-2') safety = 5 while not self._rtc.synced() and safety > 0: # Wait for NTP time sync, max 5s time.sleep(1) safety -= 1 self._last_update = self._rtc.now() self._log('Sync NTP... {0}'.format('Done' if safety else 'Fail')) self._tft.text(0, 14, ' ' * 50, self._tft.DARKGREY) # Clear the line def _process_data(self, message): """ Process MQTT message """ topic = message[1] data = float(message[2]) # Collect data samples from solar & grid if topic == self._solar_topic: self._solar = max(0, data) self._data_counter += 1 elif topic == self._grid_topic: self._grid = data self._data_counter += 1 if self._data_counter == 2: # Once the data has been received, calculate realtime usage self._usage = self._solar + self._grid self._last_update = self._rtc.now() self._realtime_updated = True # Redraw realtime values self._data_counter = 0 # Process data for the graph; collect solar & grids, and every x-pixel # average the data out and draw them on that pixel. now = time.time() rounded_now = now - now % self._graph_interval if self._last_value_added is None: self._last_value_added = rounded_now self._solar_avg_buffer.append(self._solar) self._grid_avg_buffer.append(self._grid) if self._last_value_added != rounded_now and len( self._solar_avg_buffer) > 0: solar = sum(self._solar_avg_buffer) / len( self._solar_avg_buffer) self._solar_avg_buffer = [] grid = sum(self._grid_avg_buffer) / len(self._grid_avg_buffer) self._grid_avg_buffer = [] usage = solar + grid self._solar_buffer.append(solar) self._solar_buffer = self._solar_buffer[-320:] self._usage_buffer.append(usage) self._usage_buffer = self._usage_buffer[-320:] self._last_value_added = rounded_now self._buffer_updated = True # Redraw the graph def run(self): """ Set timer """ self._timer.init(period=self._update_interval, mode=Timer.PERIODIC, callback=self._tick) def _tick(self, timer): """ Do stuff at a regular interval """ _ = timer try: # At avery ticket, update display's relevant parts self._draw() except Exception as ex: self._log('Exception in draw: {0}'.format(ex)) try: # At every tick, make sure wifi is still connected if not self._wlan.isconnected(): self.init() except Exception as ex: self._log('Exception in watchdog: {0}'.format(ex)) def _draw(self): """ Update display """ if self._realtime_updated: # Realtime part; current usage, importing/exporting and solar self._tft.text(self._tft.RIGHT, 14, ' {0:.2f}W'.format(self._solar), self._tft.YELLOW) self._tft.text(0, 14, '{0:.2f}W '.format(self._usage), self._tft.BLUE) self._importing = self._grid > 0 if self._prev_importing != self._importing: if self._importing: self._tft.text(self._tft.CENTER, 0, ' IMPORTING ', self._tft.DARKGREY) else: self._tft.text(self._tft.CENTER, 0, ' EXPORTING ', self._tft.DARKGREY) if self._importing: self._tft.text(self._tft.CENTER, 14, ' {0:.2f}W '.format(abs(self._grid)), self._tft.RED) else: self._tft.text(self._tft.CENTER, 14, ' {0:.2f}W '.format(abs(self._grid)), self._tft.GREEN) self._prev_importing = self._importing self._realtime_updated = False if self._buffer_updated: # If the graph buffers are updated, redraw the graph if len(self._usage_buffer) > 1: max_value = float( max(max(*self._solar_buffer), max(*self._usage_buffer))) else: max_value = float( max(self._solar_buffer[0], self._usage_buffer[0])) ratio = 180.0 / max_value for index, usage in enumerate(self._usage_buffer): solar = self._solar_buffer[index] usage_height = int(usage * ratio) solar_height = int(solar * ratio) max_height = max(usage_height, solar_height) self._tft.line(index, 40, index, 220 - max_height, self._tft.BLACK) if usage_height > solar_height: self._tft.line(index, 220 - usage_height, index, 220 - solar_height, self._tft.BLUE) self._tft.line(index, 220 - solar_height, index, 220, self._tft.DARKCYAN) else: self._tft.line(index, 220 - solar_height, index, 220 - usage_height, self._tft.YELLOW) self._tft.line(index, 220 - usage_height, index, 220, self._tft.DARKCYAN) self._buffer_updated = False # And in any case, update the general information at the bottom if self._blank_menu: self._tft.rect(0, 221, 320, 240, self._tft.BLACK, self._tft.BLACK) self._blank_menu = False if self._menu_horizontal_pointer == 0: data = ' Updated: {0:04d}/{1:02d}/{2:02d} {3:02d}:{4:02d}:{5:02d} '.format( *self._last_update[:6]) elif self._menu_horizontal_pointer == 1: data = ' Battery: {0}% '.format(self._battery.level) elif self._menu_horizontal_pointer == 2: data = ' Width: {0} '.format(self._graph_window) else: data = ' Graph entries: {0} '.format(len(self._usage_buffer)) self._tft.text(0, self._tft.BOTTOM, '<', self._tft.DARKGREY) self._tft.text(self._tft.RIGHT, self._tft.BOTTOM, '>', self._tft.DARKGREY) self._tft.text(self._tft.CENTER, self._tft.BOTTOM, data, self._tft.DARKGREY) def _button_a_pressed(self, pin, pressed): if pressed: self._menu_horizontal_pointer -= 1 if self._menu_horizontal_pointer < 0: self._menu_horizontal_pointer = 3 self._blank_menu = True def _button_c_pressed(self, pin, pressed): if pressed: self._menu_horizontal_pointer += 1 if self._menu_horizontal_pointer > 3: self._menu_horizontal_pointer = 0 self._blank_menu = True @staticmethod def _shorten(seconds): """ Converts seconds to a `xh ym ys` notation """ parts = [] seconds_hour = 60 * 60 seconds_minute = 60 if seconds >= seconds_hour: hours = int((seconds - seconds % seconds_hour) / seconds_hour) seconds = seconds - (hours * seconds_hour) parts.append('{0}h'.format(hours)) if seconds >= seconds_minute: minutes = int( (seconds - seconds % seconds_minute) / seconds_minute) seconds = seconds - (minutes * seconds_minute) parts.append('{0}m'.format(minutes)) if seconds > 0: parts.append('{0}s'.format(seconds)) return ' '.join(parts) def _log(self, message, tft=False): """ Logs a message to the console and (optionally) to the display """ print(message) if tft: self._tft.text(0, 14, '{0}{1}'.format(message, ' ' * 50), self._tft.DARKGREY)
adc = machine.ADC() # create an ADC object apin = adc.channel(pin='P16', attn=adc.ATTN_2_5DB) # create an analog pin on P16 pycom.heartbeat(False) # Setup Connection wifi = handler.WifiHandler() wifi.connect() rtc = RTC() rtc.ntp_sync("dk.pool.ntp.org") rtcerrorcount = 0 # Wait for the NTP sync while (not rtc.synced()): time.sleep(1) rtcerrorcount += 1 if (rtcerrorcount > 60): pycom.rgbled(0xFF0000) running = False machine.reset() from geoposition import geolocate ssid_ = config.wifi_ssid google_api_key = config.google_api_key # from google geo_locate = geolocate(google_api_key, ssid_) #geo_locate object valid, location = geo_locate.get_location() if (valid):
class DatacakeGateway: def machine_callback(self, arg): evt = machine.events() if (evt & machine.PYGATE_START_EVT): self.machine_state = config.GATEWAY_STATE_OK pycom.rgbled(config.RGB_GATEWAY_OK) elif (evt & machine.PYGATE_ERROR_EVT): self.machine_state = config.GATEWAY_STATE_ERROR pycom.rgbled(config.RGB_GATEWAY_ERROR) elif (evt & machine.PYGATE_STOP_EVT): self.machine_state = config.GATEWAY_STATE_STOP pycom.rgbled(config.RGB_GATEWAY_STOP) def __init__(self): print("Init: Initialization of Gateway class...") # Machine machine.callback( trigger=(machine.PYGATE_START_EVT | machine.PYGATE_STOP_EVT | machine.PYGATE_ERROR_EVT), handler=self.machine_callback) self.machine_state = 0 # LTE self.lte = LTE() self.lte_connection_state = 0 # RTC self.rtc = RTC() # Gateway # Read the GW config file from Filesystem self.gateway_config_file = None # Timers self.rgb_breathe_timer = Timer.Chrono() # Startup # Should be called outside init # self.start_up() def lte_event_callback(self, arg): #self.blink_rgb_led(5, 0.25, config.RGB_LTE_ERROR) #self.lte.deinit() #machine.reset() print( "\n\n\n#############################################################" ) print("CB LTE Callback Handler") ev = arg.events() # NB: reading the events clears them t = time.ticks_ms() print("CB", t, time.time(), ev, time.gmtime()) self.blink_rgb_led(3, 0.25, config.RGB_LTE_ERROR) if ev & LTE.EVENT_COVERAGE_LOSS: print("CB", t, "coverage loss") if ev & LTE.EVENT_BREAK: print("CB", t, "uart break signal") try: self.lte.pppsuspend() if not self.lte.isattached(): print("not attached ... reattach") self.lte.detach() self.init_lte() else: print("attached ... resume") self.lte.pppresume() except Exception as ex: sys.print_exception(ex) print( "#############################################################\n\n\n" ) def init_gateway(self): print("Init GW: Starting LoRaWAN Concentrator...") try: self.gateway_config_file = open(config.GW_CONFIG_FILE_PATH, 'r').read() except Exception as e: print("Error opening Gateway Config: {}".format(e)) # TODO: Handle Error return False else: machine.pygate_init(self.gateway_config_file) print("Init GW: LoRaWAN Concentrator UP!") return True def init_rtc(self): print("Init RTC: Syncing RTC...") try: self.rtc.ntp_sync(server="pool.ntp.org") while not self.rtc.synced(): self.blink_rgb_led(1, 0.25, config.RGB_RTC_IS_SYNCING, delay_end=False) self.blink_rgb_led(3, 0.1, config.RGB_RTC_IS_SYNCING) except Exception as e: print("Exception syncing RTC: {}".format(e)) return False else: print("Init RTC: Synced!") return True def init_lte(self): self.lte_connection_state = 0 self.lte.init() #self.lte.lte_callback(LTE.EVENT_COVERAGE_LOSS, self.lte_event_callback) self.lte.lte_callback(LTE.EVENT_BREAK, self.lte_event_callback) while True: # attach LTE if self.lte_connection_state == 0: print("Init LTE: Attaching LTE...") self.lte.attach(band=config.LTE_BAND, apn=config.LTE_APN) while not self.lte.isattached(): self.blink_rgb_led(1, 0.25, config.RGB_LTE_IS_ATTACHING, delay_end=False) self.blink_rgb_led(3, 0.1, config.RGB_LTE_IS_ATTACHING) self.lte_connection_state += 1 print("Init LTE: Attached!") # connect LTE if self.lte_connection_state == 1: print("Init LTE: Connecting LTE...") self.lte.connect() while not self.lte.isconnected(): self.blink_rgb_led(1, 0.25, config.RGB_LTE_IS_CONNECTING, delay_end=False) self.blink_rgb_led(3, 0.1, config.RGB_LTE_IS_CONNECTING) self.lte_connection_state += 1 print("Init LTE: Connected!") # done if self.lte_connection_state == 2: return True def blink_rgb_led(self, times, speed, color_on, color_off=config.RGB_OFF, delay_end=True): for index in range(times): pycom.rgbled(config.RGB_OFF) time.sleep(speed) pycom.rgbled(color_on) time.sleep(speed) pycom.rgbled(config.RGB_OFF) if delay_end is True: time.sleep(0.1) def start_up(self): print("Start Up: Now starting up Gateway...") self.init_lte() self.init_rtc() self.init_gateway() #self.main_loop() def main_loop(self): # Start Timers self.rgb_breathe_timer.start() while True: if self.rgb_breathe_timer.read( ) > config.TIMER_RGB_BREATHE_INTERVAL: self.rgb_breathe_timer.reset()
class BootScene: """ This module implements a boot scene for Pycom modules """ def __init__(self, display, config): """ Initialize the module. `display` is saved as an instance variable because it is needed to update the display via self.display.put_pixel() and .render() """ self.display = display self.debug = False self.intensity = 16 self.rtc = RTC() self.wlan = WLAN() if not config: return if 'debug' in config: self.debug = config['debug'] if 'intensity' in config: self.intensity = int(round(config['intensity'] * 255)) def reset(self): """ This method is called before transitioning to this scene. Use it to (re-)initialize any state necessary for your scene. """ pass def set_intensity(self, value=None): if value is not None: self.intensity -= 1 if not self.intensity: self.intensity = 16 return self.intensity def input(self, button_state): """ Handle button input """ return 0 # signal that we did not handle the input def render(self, frame, dropped_frames, fps): """ Render the scene. This method is called by the render loop with the current frame number, the number of dropped frames since the previous invocation and the requested frames per second (FPS). """ dots = str('.' * ((frame % 3) + 1)) if not self.wlan.isconnected(): if not frame: dots = '?' text = 'wifi{}'.format(dots) elif not self.rtc.synced(): text = 'clock{}'.format(dots) else: text = 'loading' display = self.display intensity = self.intensity display.render_text(PixelFont, text, 1, 1, intensity) display.render() return True
ssid = "ssid" password = "******" station = network.WLAN(network.STA_IF) station.active(True) station.connect(ssid, password) while station.isconnected() == False: pass print("Connection successful") print(station.ifconfig()) rtc = RTC() rtc.ntp_sync(server="hr.pool.ntp.org", tz="CST-8") while rtc.synced() == False: print('sync rtc now...') time.sleep(1) print('sync success') utime.localtime() i2c = I2C(scl=22, sda=21) r = pcf8563.PCF8563(i2c) print('rtc time') r.datetime() time.sleep(1) print('sync system to pcf8563') r.write_now() while True:
class Monitor(object): def __init__( self, solar_topic, grid_topic, mqtt_broker, wifi_credentials, graph_interval_s=60, update_interval_ms=1000 ): self._solar_topic = solar_topic self._grid_topic = grid_topic self._mqtt_broker = mqtt_broker self._wifi_credentials = wifi_credentials self._graph_interval = graph_interval_s self._update_interval = update_interval_ms self._graph_window = Monitor._shorten(self._graph_interval * 320) self._tft = None self._wlan = None self._mqtt = None self._neopixel = None self._battery = IP5306(I2C(scl=Pin(22), sda=Pin(21))) self._timer = Timer(0) self._rtc = RTC() self._button_a = ButtonA(callback=self._button_a_pressed) self._button_b = ButtonB(callback=self._button_b_pressed) self._button_c = ButtonC(callback=self._button_c_pressed) self._reboot = False self._backup = False self._solar = None self._usage = None self._grid = None self._importing = None self._prev_importing = None self._solar_avg_buffer = [] self._grid_avg_buffer = [] self._usage_buffer = [] self._usage_buffer_max = 0 self._usage_buffer_min = 0 self._usage_buffer_avg = 0 self._usage_buffer_stddev = 0 self._usage_max_coords = [0, 0] self._calculate_buffer_stats('usage', 0) self._solar_buffer = [] self._solar_buffer_max = 0 self._solar_buffer_min = 0 self._solar_buffer_avg = 0 self._solar_buffer_stddev = 0 self._solar_max_coords = [0, 0] self._calculate_buffer_stats('solar', 0) self._last_update = (0, 0, 0, 0, 0, 0) self._data_received = [False, False] self._buffer_updated = False self._realtime_updated = False self._last_value_added = None self._graph_max = 0 self._solar_max = 0 self._usage_max = 0 self._menu_horizontal_pointer = 0 self._menu_tick = 0 self._menu_tick_divider = 0 self._blank_menu = False self._save = False self._show_markers = True self._color = None self._ticks = {'M': 0, # MQTT message 'D': 0, # Data sample (solar + grid) 'R': 0, # Remaining time for next graph update 'G': 0, # Graph datapoint added 'B': 0, # Button press 'E': 0} # Exceptions self._tick_keys = ['M', 'D', 'G', 'B', 'R', 'E'] self._last_exception = 'None' self._runtime_config_parameters = ['show_markers'] self._last_logline = '' self._log('Initializing TFT...') self._tft = display.TFT() self._tft.init(self._tft.M5STACK, width=240, height=320, rst_pin=33, backl_pin=32, miso=19, mosi=23, clk=18, cs=14, dc=27, bgr=True, backl_on=1) self._tft.tft_writecmd(0x21) # Invert colors self._tft.clear() self._tft.font(self._tft.FONT_Default, transparent=False) self._tft.text(0, 0, 'USAGE', self._tft.DARKGREY) self._tft.text(self._tft.CENTER, 0, 'IMPORTING', self._tft.DARKGREY) self._tft.text(self._tft.RIGHT, 0, 'SOLAR', self._tft.DARKGREY) self._tft.text(0, 14, 'Loading...', self._tft.DARKGREY) self._log('Initializing TFT... Done') def init(self): """ Init logic; connect to wifi, connect to MQTT and setup RTC/NTP """ self._log('Connecting to wifi ({0})... '.format(self._wifi_credentials[0]), tft=True) self._wlan = network.WLAN(network.STA_IF) self._wlan.active(True) self._wlan.connect(*self._wifi_credentials) safety = 10 while not self._wlan.isconnected() and safety > 0: # Wait for the wifi to connect, max 10s time.sleep(1) safety -= 1 self._log('Connecting to wifi ({0})... {1}'.format(self._wifi_credentials[0], 'Done' if safety else 'Fail')) mac_address = ubinascii.hexlify(self._wlan.config('mac'), ':').decode() self._log('Connecting to MQTT...', tft=True) if self._mqtt is not None: self._mqtt.unsubscribe('emon/#') self._mqtt = network.mqtt('emon', self._mqtt_broker, user='******', password='******', clientid=mac_address, data_cb=self._process_data) self._mqtt.start() safety = 5 while self._mqtt.status()[0] != 2 and safety > 0: # Wait for MQTT connection, max 5s time.sleep(1) safety -= 1 self._mqtt.subscribe('emon/#') self._log('Connecting to MQTT... {0}'.format('Done' if safety else 'Fail')) self._log('Sync NTP...', tft=True) self._rtc.ntp_sync(server='be.pool.ntp.org', tz='CET-1CEST-2') safety = 5 while not self._rtc.synced() and safety > 0: # Wait for NTP time sync, max 5s time.sleep(1) safety -= 1 self._last_update = self._rtc.now() self._log('Sync NTP... {0}'.format('Done' if safety else 'Fail')) self._log('Initializing Neopixels...', tft=True) try: self._neopixel = Neopixel(Pin(15), 10, Neopixel.TYPE_RGB) self._neopixel.clear() except Exception: self._neopixel = None self._log('Initializing Neopixels... {0}'.format('Available' if self._neopixel is not None else 'Unavailable')) self._tft.text(0, 14, ' ' * 50, self._tft.DARKGREY) # Clear the line def _process_data(self, message): """ Process MQTT message """ try: topic = message[1] data = float(message[2]) self._ticks['M'] += 1 # Collect data samples from solar & grid if topic == self._solar_topic: self._solar = max(0.0, data) self._data_received[0] = True elif topic == self._grid_topic: self._grid = data self._data_received[1] = True if self._data_received[0] and self._data_received[1]: self._ticks['D'] += 1 # Once the data has been received, calculate realtime usage self._usage = self._solar + self._grid self._last_update = self._rtc.now() self._realtime_updated = True # Redraw realtime values self._data_received = [False, False] # Process data for the graph; collect solar & grids, and every x-pixel # average the data out and draw them on that pixel. now = time.time() rounded_now = int(now - now % self._graph_interval) if self._last_value_added is None: self._last_value_added = rounded_now self._ticks['R'] = int(rounded_now + self._graph_interval - now) self._solar_avg_buffer.append(int(self._solar)) self._grid_avg_buffer.append(int(self._grid)) if self._last_value_added != rounded_now: self._ticks['G'] += 1 solar, usage = self._read_avg_buffer(reset=True) self._solar_buffer.append(solar) self._solar_buffer = self._solar_buffer[-319:] # Keep one pixel for moving avg self._calculate_buffer_stats('solar', solar) self._usage_buffer.append(usage) self._usage_buffer = self._usage_buffer[-319:] # Keep one pixel for moving avg self._calculate_buffer_stats('usage', usage) self._last_value_added = rounded_now self._buffer_updated = True # Redraw the complete graph except Exception as ex: self._last_exception = str(ex) self._ticks['E'] += 1 self._log('Exception in process data: {0}'.format(ex)) def _calculate_buffer_stats(self, buffer_type, single_value): buffer = getattr(self, '_{0}_buffer'.format(buffer_type)) if len(buffer) == 0: return setattr(self, '_{0}_buffer_max'.format(buffer_type), single_value if len(buffer) == 1 else max(*buffer)) setattr(self, '_{0}_buffer_min'.format(buffer_type), single_value if len(buffer) == 1 else min(*buffer)) setattr(self, '_{0}_buffer_avg'.format(buffer_type), sum(buffer) / len(buffer)) setattr(self, '_{0}_buffer_stddev'.format(buffer_type), Monitor._stddev(buffer)) def _read_avg_buffer(self, reset): solar_avg_buffer_length = len(self._solar_avg_buffer) grid_avg_buffer_length = len(self._grid_avg_buffer) if solar_avg_buffer_length == 0 or grid_avg_buffer_length == 0: return 0, 0 solar = int(sum(self._solar_avg_buffer) / solar_avg_buffer_length) grid = int(sum(self._grid_avg_buffer) / grid_avg_buffer_length) usage = solar + grid if reset: self._solar_avg_buffer = [] self._grid_avg_buffer = [] return solar, usage def load(self): self._log('Loading runtime configuration...', tft=True) if 'runtime_config.json' in os.listdir('/flash'): with open('/flash/runtime_config.json', 'r') as f: runtime_config = ujson.load(f) for key in self._runtime_config_parameters: if key in runtime_config: setattr(self, '_{0}'.format(key), runtime_config[key]) self._log('Loading runtime configuration... Done', tft=True) self._log('Restoring backup...', tft=True) if 'backup.json' in os.listdir('/flash'): with open('/flash/backup.json', 'r') as f: backup = ujson.load(f) self._usage_buffer = backup.get('usage_buffer', []) self._calculate_buffer_stats('usage', 0) self._solar_buffer = backup.get('solar_buffer', []) self._calculate_buffer_stats('solar', 0) os.remove('/flash/backup.json') self._log('Restoring backup... Done', tft=True) def run(self): """ Set timer """ self._timer.init(period=self._update_interval, mode=Timer.PERIODIC, callback=self._tick) def _tick(self, timer): """ Do stuff at a regular interval """ _ = timer self._draw() try: # At every tick, make sure wifi is still connected if not self._wlan.isconnected(): self.init() except Exception as ex: self._last_exception = str(ex) self._ticks['E'] += 1 self._log('Exception in watchdog: {0}'.format(ex)) if self._reboot: self._take_backup() self._save_runtime_config() machine.reset() if self._backup: self._take_backup() self._save_runtime_config() self._backup = False if self._save: self._save_runtime_config() self._save = False def _save_runtime_config(self): data = {} for key in self._runtime_config_parameters: data[key] = getattr(self, '_{0}'.format(key)) with open('/flash/runtime_config.json', 'w') as runtime_config_file: runtime_config_file.write(ujson.dumps(data)) def _take_backup(self): with open('/flash/backup.json', 'w') as backup_file: backup_file.write(ujson.dumps({'usage_buffer': self._usage_buffer, 'solar_buffer': self._solar_buffer})) def _draw(self): """ Update display """ try: self._draw_realtime() except Exception as ex: self._last_exception = str(ex) self._ticks['E'] += 1 self._log('Exception in draw realtime: {0}'.format(ex)) try: self._draw_graph() except Exception as ex: self._last_exception = str(ex) self._ticks['E'] += 1 self._log('Exception in draw graph: {0}'.format(ex)) try: self._draw_menu() except Exception as ex: self._last_exception = str(ex) self._ticks['E'] += 1 self._log('Exception in draw menu: {0}'.format(ex)) try: self._draw_rgb() except Exception as ex: self._last_exception = str(ex) self._ticks['E'] += 1 self._log('Exception in draw rgb: {0}'.format(ex)) def _draw_rgb(self): """ Uses the neopixel leds (if available) to indicate how "good" our power consumption is. """ if self._neopixel is None: return if len(self._solar_buffer) == 0 or self._usage is None: self._neopixel.clear() return high_usage = self._usage > self._usage_buffer_avg + (self._usage_buffer_stddev * 2) if self._grid < 0: # Feeding back to the grid score = 0 if self._grid < -500: score += 1 if self._grid < -1000: score += 1 if high_usage: score -= 1 colors = [Neopixel.GREEN, Neopixel.LIME, Neopixel.YELLOW] color = colors[max(0, score)] else: score = 0 if high_usage: score += 1 if self._solar == 0: score += 1 colors = [Neopixel.BLUE, Neopixel.PURPLE, Neopixel.RED] color = colors[max(0, score)] if self._color != color: self._neopixel.set(0, color, num=10) self._color = color def _draw_realtime(self): """ Realtime part; current usage, importing/exporting and solar """ if not self._realtime_updated: return self._tft.text(self._tft.RIGHT, 14, ' {0:.2f}W'.format(self._solar), self._tft.YELLOW) self._tft.text(0, 14, '{0:.2f}W '.format(self._usage), self._tft.BLUE) self._importing = self._grid > 0 if self._prev_importing != self._importing: if self._importing: self._tft.text(self._tft.CENTER, 0, ' IMPORTING ', self._tft.DARKGREY) else: self._tft.text(self._tft.CENTER, 0, ' EXPORTING ', self._tft.DARKGREY) if self._importing: self._tft.text(self._tft.CENTER, 14, ' {0:.2f}W '.format(abs(self._grid)), self._tft.RED) else: self._tft.text(self._tft.CENTER, 14, ' {0:.2f}W '.format(abs(self._grid)), self._tft.GREEN) self._prev_importing = self._importing self._realtime_updated = False def _draw_graph(self): """ Draw the graph part """ solar_moving_avg, usage_moving_avg = self._read_avg_buffer(reset=False) solar_max = max(self._solar_buffer_max, solar_moving_avg) usage_max = max(self._usage_buffer_max, usage_moving_avg) max_value = float(max(solar_max, usage_max)) if max_value != self._graph_max: self._graph_max = max_value self._buffer_updated = True if solar_max != self._solar_max: self._solar_max = solar_max self._buffer_updated = True if usage_max != self._usage_max: self._usage_max = usage_max self._buffer_updated = True ratio = 1 if max_value == 0 else (180.0 / max_value) show_markers = self._show_markers and max_value > 0 buffer_size = len(self._usage_buffer) avg_marker = False usage_max_coords = self._usage_max_coords solar_max_coords = self._solar_max_coords if self._buffer_updated: for index, usage in enumerate(self._usage_buffer): solar = self._solar_buffer[index] usage_y, solar_y = self._draw_graph_line(index, solar, usage, ratio) if usage == usage_max: usage_max_coords = [index, usage_y] if solar == solar_max: solar_max_coords = [index, solar_y] usage_y, solar_y = self._draw_graph_line(buffer_size, solar_moving_avg, usage_moving_avg, ratio) if usage_moving_avg == usage_max: avg_marker = True usage_max_coords = [buffer_size, usage_y] if solar_moving_avg == solar_max: avg_marker = True solar_max_coords = [buffer_size, solar_y] max_coords_changed = self._usage_max_coords != usage_max_coords or self._solar_max_coords != solar_max_coords if self._buffer_updated and max_coords_changed: self._tft.rect(buffer_size + 1, 40, 320, 220, self._tft.BLACK, self._tft.BLACK) if show_markers: self._draw_marker('{0:.0f}W'.format(solar_max), solar_max_coords, not avg_marker) self._draw_marker('{0:.0f}W'.format(usage_max), usage_max_coords, not avg_marker) self._usage_max_coords = usage_max_coords self._solar_max_coords = solar_max_coords self._buffer_updated = False def _draw_marker(self, text, coords, transparent): x, y = coords if x > 160: text_x = x - self._tft.textWidth(text) - 10 line_start_x = x - 2 line_end_x = x - 8 else: text_x = x + 10 line_start_x = x + 2 line_end_x = text_x - 2 if y > 120: text_y = y - 22 else: text_y = y + 10 self._tft.font(self._tft.FONT_Default, transparent=transparent) self._tft.text(text_x, text_y, text, self._tft.DARKGREY) self._tft.line(line_start_x, y, line_end_x, text_y + 6, self._tft.DARKGREY) self._tft.font(self._tft.FONT_Default, transparent=False) def _draw_graph_line(self, index, solar, usage, ratio): usage_height = int(usage * ratio) solar_height = int(solar * ratio) usage_y = 220 - usage_height solar_y = 220 - solar_height max_height = max(usage_height, solar_height) self._tft.line(index, 40, index, 220 - max_height, self._tft.BLACK) if usage_height > solar_height: self._tft.line(index, usage_y, index, solar_y, self._tft.BLUE) if solar_height > 0: self._tft.line(index, solar_y, index, 220, self._tft.DARKCYAN) else: self._tft.line(index, solar_y, index, usage_y, self._tft.YELLOW) if usage_height > 0: self._tft.line(index, usage_y, index, 220, self._tft.DARKCYAN) return usage_y, solar_y def _draw_menu(self): if self._blank_menu: self._tft.rect(0, 221, 320, 240, self._tft.BLACK, self._tft.BLACK) self._blank_menu = False if self._menu_horizontal_pointer == 0: data = 'Updated: {0:04d}/{1:02d}/{2:02d} {3:02d}:{4:02d}:{5:02d}'.format(*self._last_update[:6]) elif self._menu_horizontal_pointer == 1: data = 'Battery: {0}%'.format(self._battery.level) elif self._menu_horizontal_pointer == 2: data = 'Graph: {0} {1}, max {2:.2f}W'.format(len(self._usage_buffer), self._graph_window, self._graph_max) elif self._menu_horizontal_pointer in [3, 4]: data_type = 'solar' if self._menu_horizontal_pointer == 3 else 'usage' solar, usage = self._read_avg_buffer(reset=False) if self._menu_tick == 0: value = min( getattr(self, '_{0}_buffer_min'.format(data_type)), solar if data_type == 'solar' else usage, self._solar if data_type == 'solar' else self._usage ) info = 'min' elif self._menu_tick == 1: value = getattr(self, '_{0}_buffer_avg'.format(data_type)) info = 'avg' elif self._menu_tick == 2: value = getattr(self, '_{0}_buffer_avg'.format(data_type)) + (getattr(self, '_{0}_buffer_stddev'.format(data_type)) * 2) info = 'high' else: value = max( getattr(self, '_{0}_buffer_max'.format(data_type)), solar if data_type == 'solar' else usage, self._solar if data_type == 'solar' else self._usage ) info = 'max' data = '{0}{1} stats: {2:.2f}W {3}'.format(data_type[0].upper(), data_type[1:], value, info) elif self._menu_horizontal_pointer == 5: data = 'Time: {0}'.format(time.time()) elif self._menu_horizontal_pointer == 6: data = 'Exception: {0}'.format(self._last_exception[:20]) elif self._menu_horizontal_pointer == 7: data = 'Press B to reboot' elif self._menu_horizontal_pointer == 8: data = 'Press B to take a backup' elif self._menu_horizontal_pointer == 9: data = 'Press B to {0} markers'.format('hide' if self._show_markers else 'show') elif self._menu_horizontal_pointer == 10: log_entry = self._last_logline[:26] if len(log_entry) < 26: log_entry += ' ' * (26 - len(log_entry)) data = 'Log: {0}'.format(log_entry) else: data = 'Ticks: {0}'.format(', '.join('{0}'.format(self._ticks[key]) for key in self._tick_keys)) self._tft.text(0, self._tft.BOTTOM, '<', self._tft.DARKGREY) self._tft.text(self._tft.RIGHT, self._tft.BOTTOM, '>', self._tft.DARKGREY) if len(data) < 32: padding = int(float(32 - len(data) + 1) / 2) data = '{0}{1}{2}'.format(' ' * padding, data, ' ' * padding) self._tft.text(self._tft.CENTER, self._tft.BOTTOM, data, self._tft.DARKGREY) self._menu_tick_divider += 1 if self._menu_tick_divider == 3: # Increase menu tick every X seconds self._menu_tick += 1 if self._menu_tick == 4: self._menu_tick = 0 self._menu_tick_divider = 0 def _button_a_pressed(self, pin, pressed): _ = pin if pressed: self._ticks['B'] += 1 self._menu_horizontal_pointer -= 1 if self._menu_horizontal_pointer < 0: self._menu_horizontal_pointer = 11 self._blank_menu = True def _button_b_pressed(self, pin, pressed): _ = pin if pressed: if self._menu_horizontal_pointer == 7: self._reboot = True elif self._menu_horizontal_pointer == 8: self._backup = True elif self._menu_horizontal_pointer == 9: self._show_markers = not self._show_markers self._save = True def _button_c_pressed(self, pin, pressed): _ = pin if pressed: self._ticks['B'] += 1 self._menu_horizontal_pointer += 1 if self._menu_horizontal_pointer > 11: self._menu_horizontal_pointer = 0 self._blank_menu = True @staticmethod def _stddev(entries): """ returns the standard deviation of lst """ avg = sum(entries) / len(entries) variance = sum([(e - avg) ** 2 for e in entries]) / len(entries) return sqrt(variance) @staticmethod def _shorten(seconds): """ Converts seconds to a `xh ym ys` notation """ parts = [] seconds_hour = 60 * 60 seconds_minute = 60 if seconds >= seconds_hour: hours = int((seconds - seconds % seconds_hour) / seconds_hour) seconds = seconds - (hours * seconds_hour) parts.append('{0}h'.format(hours)) if seconds >= seconds_minute: minutes = int((seconds - seconds % seconds_minute) / seconds_minute) seconds = seconds - (minutes * seconds_minute) parts.append('{0}m'.format(minutes)) if seconds > 0: parts.append('{0}s'.format(seconds)) return ' '.join(parts) def _log(self, message, tft=False): """ Logs a message to the console and (optionally) to the display """ print(message) self._last_logline = message if tft: self._tft.text(0, 14, '{0}{1}'.format(message, ' ' * 50), self._tft.DARKGREY)
print("start telnet server") # Change telnet.start(user='******', password='******') # fetch NTP time from machine import RTC print("inquire RTC time") rtc = RTC() rtc.ntp_sync(server="pool.ntp.org") timeout = 10 for _ in range(timeout): if rtc.synced(): break print("Waiting for rtc time") time.sleep(1) if rtc.synced(): print(time.strftime("%c", time.localtime())) else: print("could not get NTP time") d = Pin(LED, mode = Pin.OUT) analog_pin = ADC(Pin(33)) # corresponds to pin A9 ADC pin analog_pin.atten(ADC.ATTN_11DB)
class TerkinDevice: def __init__(self, name=None, version=None, settings=None): self.name = name self.version = version self.settings = settings # Conditionally enable terminal on UART0. Default: False. self.terminal = Terminal(self.settings) self.terminal.start() self.device_id = get_device_id() self.networking = None self.telemetry = None self.wdt = None self.rtc = None self.status = DeviceStatus() @property def appname(self): return '{} {}'.format(self.name, self.version) def start_networking(self): log.info('Starting networking') from terkin.network import NetworkManager, WiFiException self.networking = NetworkManager(device=self, settings=self.settings) # Start WiFi. try: self.networking.start_wifi() # Wait for network interface to come up. self.networking.wait_for_nic() self.status.networking = True except WiFiException: log.error('Network connectivity not available, WiFi failed') self.status.networking = False # Start UDP server for pulling device into maintenance mode. self.networking.start_modeserver() # Initialize LoRa device. if self.settings.get('networking.lora.antenna_attached'): try: self.networking.start_lora() except: log.exception('Unable to start LoRa subsystem') else: log.info( "[LoRa] Disabling LoRa interface as no antenna has been attached. " "ATTENTION: Running LoRa without antenna will wreck your device." ) # Inform about networking status. #self.networking.print_status() def start_watchdog(self): """ The WDT is used to restart the system when the application crashes and ends up into a non recoverable state. After enabling, the application must "feed" the watchdog periodically to prevent it from expiring and resetting the system. """ # https://docs.pycom.io/firmwareapi/pycom/machine/wdt.html if not self.settings.get('main.watchdog.enabled', False): log.info('Skipping watchdog timer (WDT)') return watchdog_timeout = self.settings.get('main.watchdog.timeout', 10000) log.info('Starting the watchdog timer (WDT) with timeout {}ms'.format( watchdog_timeout)) from machine import WDT self.wdt = WDT(timeout=watchdog_timeout) # Feed Watchdog once. self.wdt.feed() def feed_watchdog(self): if self.wdt is not None: log.info('Feeding Watchdog') self.wdt.feed() def start_rtc(self): """ The RTC is used to keep track of the date and time. """ # https://docs.pycom.io/firmwareapi/pycom/machine/rtc.html # https://medium.com/@chrismisztur/pycom-uasyncio-installation-94931fc71283 import time from machine import RTC self.rtc = RTC() # TODO: Use values from configuration settings here. self.rtc.ntp_sync("pool.ntp.org", 360) while not self.rtc.synced(): time.sleep_ms(50) log.info('RTC: %s', self.rtc.now()) def run_gc(self): """ Run a garbage collection. https://docs.pycom.io/firmwareapi/micropython/gc.html """ import gc gc.collect() def configure_rgb_led(self): """ https://docs.pycom.io/tutorials/all/rgbled.html """ import pycom # Enable or disable heartbeat. rgb_led_heartbeat = self.settings.get('main.rgb_led.heartbeat', True) pycom.heartbeat(rgb_led_heartbeat) pycom.heartbeat_on_boot(rgb_led_heartbeat) # Alternative signalling. # Todo: Run this in a separate thread in order not to delay execution of main program flow. if not rgb_led_heartbeat: for _ in range(2): pycom.rgbled(0x001100) time.sleep(0.15) pycom.rgbled(0x000000) time.sleep(0.10) def power_off_lte_modem(self): """ We don't use LTE yet. https://community.hiveeyes.org/t/lte-modem-des-pycom-fipy-komplett-stilllegen/2161 https://forum.pycom.io/topic/4877/deepsleep-on-batteries/10 """ import pycom """ if not pycom.lte_modem_en_on_boot(): log.info('Skip turning off LTE modem') return """ log.info('Turning off LTE modem') try: from network import LTE # Invoking this will cause `LTE.deinit()` to take around 6(!) seconds. #log.info('Enabling LTE modem on boot') #pycom.lte_modem_en_on_boot(True) log.info('Turning off LTE modem on boot') pycom.lte_modem_en_on_boot(False) log.info('Invoking LTE.deinit()') lte = LTE() lte.deinit() except: log.exception('Shutting down LTE modem failed') def power_off_bluetooth(self): """ We don't use Bluetooth yet. """ log.info('Turning off Bluetooth') try: from network import Bluetooth bluetooth = Bluetooth() bluetooth.deinit() except: log.exception('Shutting down Bluetooth failed') def start_telemetry(self): log.info('Starting telemetry') self.telemetry = TelemetryManager() # Read all designated telemetry targets from configuration settings. telemetry_targets = self.settings.get('telemetry.targets') # Compute list of all _enabled_ telemetry targets. telemetry_candidates = [] for telemetry_target in telemetry_targets: if telemetry_target.get('enabled', False): telemetry_candidates.append(telemetry_target) # Create adapter objects for each enabled telemetry target. for telemetry_target in telemetry_candidates: try: self.create_telemetry_adapter(telemetry_target) self.feed_watchdog() except: log.exception( 'Creating telemetry adapter failed for target: %s', telemetry_target) def create_telemetry_adapter(self, telemetry_target): # Create adapter object. telemetry_adapter = TelemetryAdapter( device=self, endpoint=telemetry_target['endpoint'], address=telemetry_target.get('address'), data=telemetry_target.get('data'), topology=telemetry_target.get('topology'), format=telemetry_target.get('format'), content_encoding=telemetry_target.get('encode'), ) # Setup telemetry adapter. telemetry_adapter.setup() self.telemetry.add_adapter(telemetry_adapter) def enable_serial(self): # Disable these two lines if you don't want serial access. # The Pycom forum tells us that this is already incorporated into # more recent firmwares, so this is probably a thing of the past. #uart = machine.UART(0, 115200) #os.dupterm(uart) pass def print_bootscreen(self): """ Print bootscreen. This contains important details about your device and the operating system running on it. """ if not self.settings.get('main.logging.enabled', False): return # Todo: Maybe refactor to TerkinDatalogger. from uio import StringIO buffer = StringIO() def add(item=''): buffer.write(item) buffer.write('\n') # Program name and version. title = '{} {}'.format(self.name, self.version) add() add('=' * len(title)) add(title) add('=' * len(title)) # Machine runtime information. add('CPU freq {} MHz'.format(machine.freq() / 1000000)) add('Device id {}'.format(self.device_id)) add() # System memory info (in bytes) machine.info() add() # TODO: Python runtime information. add('{:8}: {}'.format('Python', sys.version)) """ >>> import os; os.uname() (sysname='FiPy', nodename='FiPy', release='1.20.0.rc7', version='v1.9.4-2833cf5 on 2019-02-08', machine='FiPy with ESP32', lorawan='1.0.2', sigfox='1.0.1') """ runtime_info = os.uname() for key in dir(runtime_info): if key == '__class__': continue value = getattr(runtime_info, key) #print('value:', value) add('{:8}: {}'.format(key, value)) add() add() # Todo: Add program authors, contributors and credits. log.info('\n' + buffer.getvalue()) def power_off(self): self.networking.stop() def hibernate(self, interval, deepsleep=False): #logging.enable_logging() if deepsleep: # Prepare and invoke deep sleep. # https://docs.micropython.org/en/latest/library/machine.html#machine.deepsleep log.info('Preparing deep sleep') # Set wake up mode. self.set_wakeup_mode() # Invoke deep sleep. log.info('Entering deep sleep for {} seconds'.format(interval)) self.terminal.stop() machine.deepsleep(int(interval * 1000)) else: log.info('Entering light sleep for {} seconds'.format(interval)) # Invoke light sleep. # https://docs.micropython.org/en/latest/library/machine.html#machine.sleep # https://docs.micropython.org/en/latest/library/machine.html#machine.lightsleep # # As "machine.sleep" seems to be a noop on Pycom MicroPython, # we will just use the regular "time.sleep" here. # machine.sleep(int(interval * 1000)) time.sleep(interval) def resume(self): log.info('Reset cause and wakeup reason: %s', MachineResetCause.humanize()) def set_wakeup_mode(self): # Set wake up parameters. """ The arguments are: - pins: a list or tuple containing the GPIO to setup for deepsleep wakeup. - mode: selects the way the configured GPIOs can wake up the module. The possible values are: machine.WAKEUP_ALL_LOW and machine.WAKEUP_ANY_HIGH. - enable_pull: if set to True keeps the pull up or pull down resistors enabled during deep sleep. If this variable is set to True, then ULP or capacitive touch wakeup cannot be used in combination with GPIO wakeup. -- https://community.hiveeyes.org/t/deep-sleep-with-fipy-esp32-on-micropython/1792/12 This will yield a wake up reason like:: 'wakeup_reason': {'code': 1, 'message': 'PIN'} """ # Todo: ``enable_pull`` or not? # From documentation. # machine.pin_sleep_wakeup(pins=['P8'], mode=machine.WAKEUP_ALL_LOW, enable_pull=True) # Let's try. #machine.pin_sleep_wakeup(pins=['P8'], mode=machine.WAKEUP_ALL_LOW, enable_pull=False) pass
class TerkinDevice: """ Singleton object for enabling different device-related subsystems and providing lowlevel routines for sleep/resume functionality. """ def __init__(self, application_info: ApplicationInfo): self.application_info = application_info self.platform_info = application_info.platform_info self.name = application_info.name self.version = application_info.version self.settings = application_info.settings self.status = DeviceStatus() self.watchdog = Watchdog(device=self, settings=self.settings) # Conditionally enable terminal on UART0. Default: False. #try: # self.terminal = Terminal(self.settings) # self.terminal.start() #except Exception as ex: # log.exc(ex, 'Enabling Terminal failed') self.device_id = get_device_id() self.networking = None self.telemetry = None self.rtc = None def start_networking(self): """ Start all configured networking devices. """ log.info('Starting networking') from terkin.network import NetworkManager, WiFiException self.networking = NetworkManager(device=self, settings=self.settings) if self.settings.get('networking.wifi.enabled'): # Start WiFi. try: self.networking.start_wifi() except Exception as ex: log.exc(ex, 'Starting WiFi networking failed') self.status.networking = False return # Wait for network stack to come up. try: self.networking.wait_for_ip_stack(timeout=5) self.status.networking = True except Exception as ex: log.exc(ex, 'IP stack not available') self.status.networking = False else: log.info("[WiFi] Interface not enabled in settings.") try: self.networking.start_services() except Exception as ex: log.exc(ex, 'Starting network services failed') # Initialize LoRa device. platform_info = self.application_info.platform_info is_pycom_lora = platform_info.device_name in ['LoPy', 'LoPy4', 'FiPy'] is_dragino = platform_info.vendor == platform_info.MICROPYTHON.RaspberryPi if self.settings.get('networking.lora.enabled'): if is_pycom_lora or is_dragino: if self.settings.get('networking.lora.antenna_attached'): try: self.networking.start_lora() self.status.networking = True except Exception as ex: log.exc(ex, 'Unable to start LoRa subsystem') self.status.networking = False else: log.info( "[LoRa] Disabling LoRa interface as no antenna has been attached. " "ATTENTION: Running LoRa without antenna will wreck your device." ) else: log.error("[LoRa] This is not a LoRa capable device.") else: log.info("[LoRa] Interface not enabled in settings.") # Initialize LTE modem. if self.settings.get('networking.lte.enabled'): try: self.networking.start_lte() self.status.networking = True except Exception as ex: log.exc(ex, 'Unable to start LTE modem') self.status.networking = False else: log.info("[LTE] Interface not enabled in settings.") # Initialize GPRS modem. if self.settings.get('networking.gprs.enabled'): try: self.networking.start_gprs() self.status.networking = True except Exception as ex: log.exc(ex, 'Unable to start GPRS modem') self.status.networking = False else: log.info("[GPRS] Interface not enabled in settings.") # Inform about networking status. #self.networking.print_status() def start_rtc(self): """ The RTC is used to keep track of the date and time. Syncs RTC with a NTP server. """ # https://docs.pycom.io/firmwareapi/pycom/machine/rtc.html # https://medium.com/@chrismisztur/pycom-uasyncio-installation-94931fc71283 import time from machine import RTC self.rtc = RTC() # TODO: Use values from configuration settings here. self.rtc.ntp_sync("pool.ntp.org", 360) while not self.rtc.synced(): time.sleep_ms(50) log.info('RTC: %s', self.rtc.now()) def run_gc(self): """ Curate the garbage collector. https://docs.pycom.io/firmwareapi/micropython/gc.html For a "quick fix", issue the following periodically. https://community.hiveeyes.org/t/timing-things-on-micropython-for-esp32/2329/9 """ import gc log.info('Start curating the garbage collector') gc.threshold(gc.mem_free() // 4 + gc.mem_alloc()) log.info('Collecting garbage') gc.collect() #log.info('Curating the garbage collector finished') log.info('Curating the garbage collector finished. Free memory: %s', gc.mem_free()) def configure_rgb_led(self): """https://docs.pycom.io/tutorials/all/rgbled.html""" if self.platform_info.vendor == self.platform_info.MICROPYTHON.Pycom: import pycom # Enable or disable heartbeat. rgb_led_heartbeat = self.settings.get('main.rgb_led.heartbeat', True) terkin_blink_pattern = self.settings.get('main.rgb_led.terkin', False) if terkin_blink_pattern: rgb_led_heartbeat = False pycom.heartbeat(rgb_led_heartbeat) pycom.heartbeat_on_boot(rgb_led_heartbeat) def blink_led(self, color, count=1): """ :param color: :param count: (Default value = 1) """ if self.platform_info.vendor == self.platform_info.MICROPYTHON.Pycom: import pycom terkin_blink_pattern = self.settings.get('main.rgb_led.terkin', False) if terkin_blink_pattern: for _ in range(count): pycom.rgbled(color) time.sleep(0.15) pycom.rgbled(0x000000) time.sleep(0.10) def start_telemetry(self): """ """ log.info('Starting telemetry') self.telemetry = TelemetryManager() # Read all designated telemetry targets from configuration settings. telemetry_targets = self.settings.get('telemetry.targets', []) # Compute list of all _enabled_ telemetry targets. telemetry_candidates = [] for telemetry_target in telemetry_targets: if telemetry_target.get('enabled', False): telemetry_candidates.append(telemetry_target) # Create adapter objects for each enabled telemetry target. for telemetry_target in telemetry_candidates: try: self.create_telemetry_adapter(telemetry_target) self.watchdog.feed() except Exception as ex: log.exc(ex, 'Creating telemetry adapter failed for target: %s', telemetry_target) def create_telemetry_adapter(self, telemetry_target): """ :param telemetry_target: """ # Create adapter object. telemetry_adapter = TelemetryAdapter(device=self, target=telemetry_target) # Setup telemetry adapter. telemetry_adapter.setup() self.telemetry.add_adapter(telemetry_adapter) def enable_serial(self): """ """ # Disable these two lines if you don't want serial access. # The Pycom forum tells us that this is already incorporated into # more recent firmwares, so this is probably a thing of the past. #uart = machine.UART(0, 115200) #os.dupterm(uart) pass def print_bootscreen(self): """Print bootscreen. This contains important details about your device and the operating system running on it. """ if not self.settings.get('main.logging.enabled', False): return # Todo: Maybe refactor to TerkinDatalogger. from uio import StringIO buffer = StringIO() def add(item=''): """ :param item: (Default value = '') """ buffer.write(item) buffer.write('\n') # Program name and version. title = '{} {}'.format(self.name, self.version) add() add('=' * len(title)) add(title) add('=' * len(title)) # Machine runtime information. frequency = machine.freq() / 1000000 add('Device id {}'.format(self.device_id)) add() add('CPU freq {} MHz'.format(frequency)) try: import pycom free_heap = pycom.get_free_heap() add('{:13}{:>7} {}'.format('Free heap', free_heap[0] / 1000.0, 'kB')) add('{:13}{:>7} {}'.format('Free PSRAM', free_heap[1] / 1000.0, 'kB')) except: pass add() # System memory info (in bytes). """ if hasattr(machine, 'info'): machine.info() add() """ # TODO: Python runtime information. add('{:8}: {}'.format('Python', sys.version.replace('\n', ''))) add('{:8}: {}'.format('platform', sys.platform)) """ >>> import os; os.uname() (sysname='FiPy', nodename='FiPy', release='1.20.0.rc7', version='v1.9.4-2833cf5 on 2019-02-08', machine='FiPy with ESP32', lorawan='1.0.2', sigfox='1.0.1') """ runtime_info = os.uname() #print(dir(runtime_info)) for key in dir(runtime_info): if key.startswith('__') or key.startswith('n_'): continue value = getattr(runtime_info, key) if callable(value): continue #print('value:', value) add('{:8}: {}'.format(key, value)) add() # Todo: Add program authors, contributors and credits. log.info('\n' + buffer.getvalue()) def power_off_lte_modem(self): """ We don't use LTE yet. Important ========= Once the LTE radio is initialized, it must be de-initialized before going to deepsleep in order to ensure minimum power consumption. This is required due to the LTE radio being powered independently and allowing use cases which require the system to be taken out from deepsleep by an event from the LTE network (data or SMS received for instance). Note ==== When using the expansion board and the FiPy together, the RTS/CTS jumpers MUST be removed as those pins are being used by the LTE radio. Keeping those jumpers in place will lead to erratic operation and higher current consumption specially while in deepsleep. -- https://forum.pycom.io/topic/3090/fipy-current-consumption-analysis/17 See also ======== - https://community.hiveeyes.org/t/lte-modem-des-pycom-fipy-komplett-stilllegen/2161 - https://forum.pycom.io/topic/4877/deepsleep-on-batteries/10 """ log.info('Turning off LTE modem') try: import pycom from network import LTE log.info('Turning off LTE modem on boot') pycom.lte_modem_en_on_boot(False) # Disables LTE modem completely. This presumably reduces the power # consumption to the minimum. Call this before entering deepsleep. log.info('Invoking LTE.deinit()') lte = LTE() lte.deinit(detach=False, reset=True) except Exception as ex: log.exc(ex, 'Shutting down LTE modem failed') def power_off_bluetooth(self): """We don't use Bluetooth yet.""" if self.platform_info.vendor == self.platform_info.MICROPYTHON.Vanilla: log.warning( "FIXME: Skip touching Bluetooth on vanilla MicroPython " "platforms as we don't use Bluetooth yet") return log.info('Turning off Bluetooth') try: from network import Bluetooth bluetooth = Bluetooth() bluetooth.deinit() except Exception as ex: log.exc(ex, 'Shutting down Bluetooth failed') def hibernate(self, interval, lightsleep=False, deepsleep=False): """ :param interval: :param lightsleep: (Default value = False) :param deepsleep: (Default value = False) """ #logging.enable_logging() if deepsleep: # Prepare and invoke deep sleep. # https://docs.micropython.org/en/latest/library/machine.html#machine.deepsleep log.info('Preparing deep sleep') # Set wake up mode. self.set_wakeup_mode() # Invoke deep sleep. log.info('Entering deep sleep for {} seconds'.format(interval)) #self.terminal.stop() machine.deepsleep(int(interval * 1000)) else: # Adjust watchdog for interval. self.watchdog.adjust_for_interval(interval) # Invoke light sleep. # https://docs.micropython.org/en/latest/library/machine.html#machine.sleep # https://docs.micropython.org/en/latest/library/machine.html#machine.lightsleep # # As "machine.sleep" seems to be a noop on Pycom MicroPython, # we will just use the regular "time.sleep" here. # machine.sleep(int(interval * 1000)) machine.idle() if lightsleep: log.info( 'Entering light sleep for {} seconds'.format(interval)) machine.sleep(int(interval * 1000)) else: # Normal wait. log.info('Waiting for {} seconds'.format(interval)) time.sleep(interval) def resume(self): """ """ try: from terkin.pycom import MachineResetCause log.info('Reset cause and wakeup reason: %s', MachineResetCause().humanize()) except Exception as ex: log.exc(ex, 'Could not determine reset cause and wakeup reason') def set_wakeup_mode(self): """ """ # Set wake up parameters. """ The arguments are: - pins: a list or tuple containing the GPIO to setup for deepsleep wakeup. - mode: selects the way the configured GPIOs can wake up the module. The possible values are: machine.WAKEUP_ALL_LOW and machine.WAKEUP_ANY_HIGH. - enable_pull: if set to True keeps the pull up or pull down resistors enabled during deep sleep. If this variable is set to True, then ULP or capacitive touch wakeup cannot be used in combination with GPIO wakeup. -- https://community.hiveeyes.org/t/deep-sleep-with-fipy-esp32-on-micropython/1792/12 This will yield a wake up reason like:: 'wakeup_reason': {'code': 1, 'message': 'PIN'} """ # Todo: ``enable_pull`` or not? # From documentation. # machine.pin_sleep_wakeup(pins=['P8'], mode=machine.WAKEUP_ALL_LOW, enable_pull=True) # Let's try. #log.info('Configuring Pin 4 for wakeup from deep sleep') #machine.pin_sleep_wakeup(pins=['P4'], mode=machine.WAKEUP_ALL_LOW, enable_pull=True) #machine.pin_sleep_wakeup(pins=['P4'], mode=machine.WAKEUP_ANY_HIGH, enable_pull=True) pass
import time import socket import time from machine import RTC TZ = 0 print("sync rtc via ntp, TZ=", TZ) rtc = RTC() print("synced?", rtc.synced()) rtc.ntp_sync('nl.pool.ntp.org') print("synced?", rtc.synced()) #time.sleep_ms(750) time.timezone(TZ * 3600) i = 0 while True: if rtc.synced(): print("rtc is synced after", i / 1000, "s") # if rtc.now()[0] == 1970: # print() break if i % 100 == 0: print(".", end="") time.sleep_ms(1) print("rtc.now", rtc.now()) print("time.gmtime", time.gmtime()) print("time.localtime", time.localtime()) print("gmt ", end=" ") print("local", end=" ")
# boot.py -- run on boot-up from machine import RTC from network import WLAN import machine import time # RTC rtc = RTC() rtc.init() # connect to wifi SSID = 'FreeTitties' passwd = 'wsxw4077' wlan = WLAN(mode=WLAN.STA, power_save=True) wlan.connect(SSID, auth=(WLAN.WPA2, passwd)) print("trying to connect to wifi") while not wlan.isconnected(): machine.idle() print("Connected to Wifin") # get ntp rtc.ntp_sync('2.fr.pool.ntp.org', update_period=3600) while not rtc.synced(): time.sleep_ms(500) print("ntp sync : " + str(rtc.synced())) wlan.disconnect() wlan.deinit()