def __engine_loop(self): time_short = 0 error_counter = 0 logger.info('Start terrariumPI engine') while self.__running: starttime = time.time() try: # Update weather self.weather.update() weather_data = self.weather.get_data() if 'hour_forecast' in weather_data and len( weather_data['hour_forecast']) > 0: self.collector.log_weather_data( weather_data['hour_forecast'][0]) # Update sensors for sensorid in self.sensors: # Update the current sensor. self.sensors[sensorid].update() # Save new data to database self.collector.log_sensor_data( self.sensors[sensorid].get_data()) # Websocket callback self.get_sensors([sensorid], socket=True) # Send notification when needed and enabled if self.sensors[sensorid].is_active( ) and self.sensors[sensorid].notification_enabled( ) and self.sensors[sensorid].get_alarm(): self.notification.message( 'sensor_alarm_' + ('low' if self.sensors[sensorid].get_current() < self.sensors[sensorid].get_alarm_min() else 'high'), self.sensors[sensorid].get_data()) # Make time for other web request sleep(0.1) # Get the current average temperatures average_data = self.get_sensors(['average'])['sensors'] # Websocket callback self.__send_message({ 'type': 'sensor_gauge', 'data': average_data }) # Update (remote) power switches for power_switch_id in self.power_switches: # Update timer trigger if activated self.power_switches[power_switch_id].timer() # Update the current sensor. self.power_switches[power_switch_id].update() # Make time for other web request sleep(0.1) # Websocket messages back self.get_uptime(socket=True) self.get_power_usage_water_flow(socket=True) self.get_environment(socket=True) self.get_audio_playing(socket=True) # Log system stats system_data = self.get_system_stats() self.collector.log_system_data(system_data) self.get_system_stats(socket=True) for webcamid in self.webcams: self.webcams[webcamid].update() sleep(0.1) except Exception, err: print err display_message = [ '%s %s' % ( _('Uptime'), terrariumUtils.format_uptime(system_data['uptime']), ), '%s %s %s %s' % (_('Load'), system_data['load']['load1'], system_data['load']['load5'], system_data['load']['load15']), '%s %.2f%s' % (_('CPU Temp.'), system_data['temperature'], self.get_temperature_indicator()) ] for env_part in average_data: alarm_icon = '!' if average_data[env_part]['alarm'] else '' display_message.append( '%s%s %.2f%s%s' % (alarm_icon, _(env_part.replace('average_', '').title()), average_data[env_part]['current'], average_data[env_part]['indicator'], alarm_icon)) self.notification.send_display(display_message) duration = (time.time() - starttime) + time_short if duration < terrariumEngine.LOOP_TIMEOUT: if error_counter > 0: error_counter -= 1 logger.info( 'Update done in %.5f seconds. Waiting for %.5f seconds for next update' % (duration, terrariumEngine.LOOP_TIMEOUT - duration)) time_short = 0 sleep(terrariumEngine.LOOP_TIMEOUT - duration) # TODO: Config setting else: error_counter += 1 if error_counter > 9: logger.error( 'Updating is having problems keeping up. Could not update in 30 seconds for %s times!' % error_counter) logger.warning( 'Updating took to much time. Needed %.5f seconds which is %.5f more then the limit %s' % (duration, duration - terrariumEngine.LOOP_TIMEOUT, terrariumEngine.LOOP_TIMEOUT)) time_short = duration - terrariumEngine.LOOP_TIMEOUT if time_short > 12: # More then 12 seconds to late.... probably never fast enough... time_short = 0
def __upgrade(self,to_version): # Set minimal version to 3.0.0 current_version = 300 table_upgrades = {'310' : ['ALTER TABLE system_data ADD COLUMN disk_total INTEGER(6)', 'ALTER TABLE system_data ADD COLUMN disk_used INTEGER(6)', 'ALTER TABLE system_data ADD COLUMN disk_free INTEGER(6)'], '380' : ['DROP INDEX IF EXISTS sensor_data_type', 'CREATE INDEX IF NOT EXISTS sensor_data_avg ON sensor_data (type, timestamp ASC)', 'DROP INDEX IF EXISTS sensor_data_id', 'CREATE INDEX IF NOT EXISTS sensor_data_id ON sensor_data (id, timestamp ASC)', 'DROP INDEX IF EXISTS switch_data_id', 'CREATE INDEX IF NOT EXISTS switch_data_id ON switch_data (id, timestamp ASC)', 'DROP INDEX IF EXISTS door_data_id', 'CREATE INDEX IF NOT EXISTS door_data_id ON door_data (id, timestamp ASC)']} try: with open('.collector.update.{}.sql'.format('393'),'r') as sql_file: table_upgrades['393'] = [line.strip() for line in sql_file.readlines()] os.remove('.collector.update.{}.sql'.format('393')) logger.warning('There are {} sensors that have an updated ID and needs to be renamed in the database. This can take a lot of time! Please wait...' .format(len(table_upgrades['393'])/2)) except IOError as ex: # No updates... just ignore pass with self.db as db: cur = db.cursor() db_version = int(cur.execute('PRAGMA user_version').fetchall()[0][0]) if db_version > current_version: current_version = db_version if current_version == to_version: logger.info('Collector database is up to date') elif current_version < to_version: logger.info('Collector database is out of date. Running updates from %s to %s' % (current_version,to_version)) # Execute updates with self.db as db: cur = db.cursor() for update_version in table_upgrades: if current_version < int(update_version) <= to_version: # Execute all updates between the versions for sql_upgrade in table_upgrades[update_version]: try: cur.execute(sql_upgrade) logger.info('Collector database upgrade for version %s succeeded! %s' % (update_version,sql_upgrade)) except Exception as ex: if 'duplicate column name' not in str(ex): logger.error('Error updating collector database. Please contact support. Error message: %s' % (ex,)) if '380' == update_version: self.__upgrade_to_380() db.commit() if int(to_version) % 10 == 0: logger.warning('Cleaning up disk space. This will take a couple of minutes depending on the database size and sd card disk speed.') filesize = os.path.getsize(terrariumCollector.DATABASE) speed = 2 # MBps duration = filesize / 1024.0 / 1024.0 / speed logger.warning('Current database is {} in size and with a speed of {}MBps it will take {} to complete'.format(terrariumUtils.format_filesize(filesize),speed,terrariumUtils.format_uptime(duration))) cur.execute('VACUUM') cur.execute('PRAGMA user_version = ' + str(to_version)) logger.info('Updated collector database. Set version to: %s' % (to_version,)) db.commit()