def __init__(self): global DISPLAY_TYPE self._current_program = -1 self._is_backlit = True self._backlight_change = datetime.datetime(9999, 12, 31) self._command = '' self._message_timeout = datetime.datetime(9999, 12, 31) self.line = [''] * LCD_ROWS self.old_line = [''] * LCD_ROWS self.position = [-LCD_LINE_DELAY] * LCD_ROWS try: if DISPLAY_TYPE == GPIO_CharLCD: # initialize display self.lcd = RPiGPIO_CharLCD(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7, LCD_COLUMNS, LCD_ROWS, LCD_BACKLIGHT) elif DISPLAY_TYPE == I2C_LCD: # initialize display self.lcd = I2C_LCD_driver.lcd(I2C_ADDRESS, I2C_BUS) # load symbol font data self._load_charset() except KeyboardInterrupt: raise except Exception: log_stderr(traceback.format_exc()) log_stderr('ERR: LCD init failed - disabling display') DISPLAY_TYPE = NONE
def get_temperature(): global temp global temp_avg_accu, temp_avg_counter, temp_avg_sum global log_temp_avg_accu, log_temp_avg_counter, log_temp_avg_sum # get temperature (moving average) # temperature is sampled n times ('get_temp'): each read is accumulated # in temp_avg_accu, with progressive weights (temp * n), # so more recent reads have priority. # At 'update_io' average temp is logged. if config.TEST_MODE > 0: temp += -10 * TEST_DELTA_EXT_INT_COEFF if io_status.heating_status == 'on' or \ io_status.heating_status == 'warming': temp += TEST_DELTA_THERMO_ON_TEMP_C # sensors delay test time.sleep(random.uniform(.0, .2)) else: temp = sensor.read_temp() # skip wrong reads (null or > 50°C) if not temp or temp > 50.0: log_stderr('Temp sensor error: received {}'.format(temp)) else: # accumulate temperature read temp_avg_counter += 1 + (.5 / task_every_secs['update_io'] / task_every_secs['get_temp']) temp_avg_sum += temp_avg_counter temp_avg_accu += temp * temp_avg_counter log_temp_avg_counter = 1 log_temp_avg_sum += log_temp_avg_counter log_temp_avg_accu += temp * log_temp_avg_counter print('Req: {:.2f}° - Int: {:.2f}° - Thermo: {}'.format( io_status.req_temp_c, temp, io_status.heating_status))
def aphorism(): aphorism = sensor.get_aphorism() try: if aphorism: io_status.aphorism_text = aphorism['quoteText'].strip() io_status.aphorism_author = aphorism['quoteAuthor'].strip() else: # just show a small mark on app if (io_status.aphorism_text and ' (*)' not in io_status.aphorism_text): io_status.aphorism_text += ' (*)' except Exception: io_status.aphorism_text = 'Error fetching aphorism' log_stderr(traceback.format_exc()) log_data('APHOEXC: {}'.format(traceback.format_exc()))
def hompi_slaves_forward_command(self, hompi_slaves, command): for slave_id, slave_data in hompi_slaves.items(): if slave_id != config.HOMPI_ID: try: command_json = json.dumps({'data': command}) request.urlopen( '{}/hompi/_send_command/{}?api_key={}'.format( slave_data['address'], request.quote(command_json), API_KEY), timeout=2) print('Forwarded COMMAND: {} to: {}'.format( command, slave_id)) except request.URLError: print('WARNING: {} server not available.'.format(slave_id)) except Exception: log_stderr(traceback.format_exc())
def __init__(self): global AMBIENT_ENABLED self._poweroff_time = datetime.datetime(9999, 12, 31) self._current_ambient_command = '' self._set_current_ambient_color('000000') try: if AMBIENT_ENABLED: self.cleanup() except KeyboardInterrupt: raise except Exception: log_stderr(traceback.format_exc()) log_stderr( '*AMBIENT ERR* : LED strip init failed - disabling AMBIENT') AMBIENT_ENABLED = False
def get_meteo(self): meteo = None try: meteo = json.load( reader( request.urlopen(self.METEO_URL.replace( '[place]', config.PLACE), timeout=5))) print(( '{} - Weather: {} - Temp.: {}° - Humidity: {}% Pressure: {} ' + 'mbar - Wind: {} m/s').format(meteo['name'], meteo['weather'][0]['main'], meteo['main']['temp'], meteo['main']['humidity'], meteo['main']['pressure'], meteo['wind']['speed'])) except request.URLError: print('WARNING: meteo not available.') except Exception: log_stderr(traceback.format_exc()) finally: return meteo
def log_data(event): try: description = '' if not event: event = 'null' else: if event == '.': # log all temperatures for id, data in io_status.hompi_slaves.items(): description += str(data['int_temp_c']) + ';' event = "'{}'".format(event.replace('\'', '\'\'')) if not description: if config.VERBOSE_LOG: description = "'{}'".format( io_status.get_output().replace('\'', '\'\'')) else: description = 'null' else: # remove last ; and add quotes description = "'{}'".format(description[:-1]) if not config.MODULE_DB_LOG: return dbmgr = db.DatabaseManager() dbmgr.query(""" INSERT INTO gm_log (datetime, int_temp_c, ext_temp_c, req_temp_c, event, description) VALUES (strftime('%s','now'), {:f}, {:f}, {:f}, {}, {}) """.format(io_status.int_temp_c, io_status.ext_temp_c, io_status.req_temp_c, event, description)) print('Logged data: {}'.format(event)) except (KeyboardInterrupt, SystemExit): raise except Exception: log_stderr('log_data error: {}'.format(traceback.format_exc())) time.sleep(1)
def meteo(): meteo = sensor.get_meteo() try: if meteo: io_status.place = io_status.weather = '' io_status.ext_temp_c = io_status.humidity = 0 io_status.pressure = io_status.wind = 0.0 io_status.place = meteo['name'] if len(meteo['weather']) > 0: io_status.weather = meteo['weather'][0]['main'] io_status.ext_temp_c = meteo['main']['temp'] io_status.humidity = meteo['main']['humidity'] io_status.pressure = meteo['main']['pressure'] io_status.wind = meteo['wind']['speed'] else: # occurs too often: just show a small mark on app if (' (*)' not in io_status.place): io_status.place += ' (*)' except (KeyError, ValueError): io_status.place = 'Error fetching meteo' log_stderr(traceback.format_exc()) log_data('METEOEXC: {}'.format(traceback.format_exc()))
def main(): global sig_command, refreshing, is_status_changed, lcd global initial_time global temp, temp_avg_accu, temp_avg_counter, temp_avg_sum global log_temp_avg_accu, log_temp_avg_counter, log_temp_avg_sum last_update_min = -1 # will sys.exit(-1) if other instance is running singleton.SingleInstance() # first initializations init() # main loop log_data('start') show_message('HOMPI', 'HOMPI START') while True: try: # save cycle start time cycle_start_time = datetime.datetime.now() secs_elapsed = round( (cycle_start_time - initial_time).total_seconds()) # time in the day current_time = datetime.datetime.today().hour * 100 + \ datetime.datetime.today().minute # refresh at end time (do once per minute) if (io_status.req_end_time == current_time and last_update_min != datetime.datetime.today().minute): last_update_min = datetime.datetime.today().minute refreshing = True # OPERATIONS NOT DONE ON REFRESH - START # update hompiS if secs_elapsed >= task_at_secs['hompi_slaves_refresh']: sensor.hompi_slaves_refresh(io_status.hompi_slaves) # update I/O: meteo if secs_elapsed >= task_at_secs['get_meteo'] \ and config.MODULE_METEO: meteo() # aphorism if secs_elapsed >= task_at_secs['get_aphorism'] \ and config.MODULE_APHORISM: aphorism() # re-sync things if secs_elapsed >= task_at_secs['refresh']: # restart LCD lcd = dashboard.Dashboard() # ambient color if config.MODULE_AMBIENT: io_status.current_ambient_color = ambient.ambient_refresh() # temp sensor failure: reset temp sampling if config.MODULE_TEMP and temp_avg_sum == 0: temp_avg_accu = temp_avg_counter = 0.0 io_status.int_temp_c = 0.0 # OPERATIONS NOT DONE ON REFRESH - END # update I/O (ack occurring here gets ambient control) if secs_elapsed >= task_at_secs['update_io'] or refreshing: process_input() # get temperature if (secs_elapsed >= task_at_secs[ 'get_temp'] or refreshing) and config.MODULE_TEMP: get_temperature() # update temperature if (secs_elapsed >= task_at_secs[ 'update_temp'] or refreshing): # save new temperature (if valid) if temp_avg_sum != 0: io_status.int_temp_c = \ round(temp_avg_accu / temp_avg_sum, 2) # reset temp sampling temp_avg_accu = temp_avg_counter = temp_avg_sum = 0 # refresh program if secs_elapsed >= task_at_secs['refresh'] or refreshing: refresh_program(current_time) # compute status (heating, switches, ...) is_status_changed |= compute_status() # update I/O: output if secs_elapsed >= task_at_secs['update_io'] or \ refreshing or is_status_changed: update_output() # log data (check task_at_mins) if (datetime.datetime.now().minute == task_at_mins[ 'log'] or refreshing) \ and log_temp_avg_sum > 0: io_status.int_temp_c = round( log_temp_avg_accu / log_temp_avg_sum, 2) log_temp_avg_accu = log_temp_avg_counter = log_temp_avg_sum = 0 log_data('refreshing' if refreshing else '.') # update LCD message (NOT ON REFRESH) if secs_elapsed >= task_at_secs['update_lcd_content']: update_lcd_content() # status speech if is_status_changed and config.MODULE_SPEECH: command = config.SPEECH_COMMAND.format( io_status.get_status_text()) + ' &' print('status changed: executing {}'.format(command)) os.system(command) except (KeyboardInterrupt, SystemExit): # cleanup sensors & LCD sensor.cleanup() lcd.cleanup() ambient.cleanup() raise except Exception: log_stderr(traceback.format_exc()) log_data('EXC: {}'.format(traceback.format_exc())) finally: # stop refreshing cycle, reset status change refreshing = is_status_changed = False # update scheduled tasks (skip any lost task) for task in task_every_secs.keys(): while secs_elapsed >= task_at_secs[task]: task_at_secs[task] += task_every_secs[task] for task in task_every_mins.keys(): if datetime.datetime.now().minute == task_at_mins[task]: task_at_mins[task] += task_every_mins[task] while task_at_mins[task] >= 60: task_at_mins[task] -= 60 # sync ambient color io_status.current_ambient_color = ambient.update() try: # update lcd screen to 1 sec approx. cycle_duration = (datetime.datetime.now() - cycle_start_time)\ .total_seconds() while cycle_duration < 1: # catch command "interrupt" (jump to new cycle) if sig_command: break frame_duration = lcd.update(io_status) if frame_duration < .25: time.sleep(.25 - frame_duration) cycle_duration += .25 if sig_command: sig_command = False refreshing = True except (KeyboardInterrupt, SystemExit): # cleanup sensors & LCD sensor.cleanup() lcd.cleanup() ambient.cleanup() raise except Exception: # LCD I/O error: refresh LCD screen log_stderr(traceback.format_exc()) log_stderr('LCD I/O error: trying to recover..') time.sleep(1) lcd = dashboard.Dashboard()