def getTheSensor(lbl, never_assume_dead=False, getHighest=False, getLowest=False): # Each sensor entry in the configuration file can be a a single item name or a python list where you can # define multiple sensor names. The first sensor in that list that has reported within the value set in # sensor_dead_after_mins will be used. (Unless never_assume_dead is set to True) # When "getHighest" argument is set to True, the sensor name with the highest value is picked. # When "getlowest" argument is set to True, the sensor name with the lowest value is picked. sensor_dead_after_mins = weatherStationUploader_configuration[ 'sensor_dead_after_mins'] # The time after which a sensor is presumed to be dead def isSensorAlive(sName): if getLastUpdate(ir.getItem(sName)).isAfter( DateTime.now().minusMinutes(sensor_dead_after_mins)): return True else: weatherStationUploader.log.warn( "Sensor device {} has not reported since: {}".format( sName, format_date(getLastUpdate(ir.getItem(sName)), customDateTimeFormats['dateTime']))) return False sensorName = None if lbl in weatherStationUploader_configuration[ 'sensors'] and weatherStationUploader_configuration['sensors'][ lbl] is not None: tSens = weatherStationUploader_configuration['sensors'][lbl] if isinstance(tSens, list): _highestValue = 0 _lowestValue = 999999999 for s in tSens: if s is None: break # Get the first sensor that is not dead and find the sensor with the highest or the lowest value if requested if never_assume_dead or isSensorAlive(s): if getHighest: _itemValue = getItemValue(s, 0) if _itemValue > _highestValue: _highestValue = _itemValue sensorName = s elif getLowest: _itemValue = getItemValue(s, 0) if _itemValue < _lowestValue: _lowestValue = _itemValue sensorName = s else: sensorName = s break else: if never_assume_dead or isSensorAlive(tSens): sensorName = tSens if sensorName is not None: weatherStationUploader.log.debug("Device used for {}: {}".format( lbl, sensorName)) return sensorName
def __init__(self, parent, zoneNumber, cfg): ''' Initialise the IdeAlarmZone class Expects: - Parent object - zoneNumber (integer) The zone's ordinal number - cfg (dictionary) The zone's configuration dictionary ''' self._armingMode = None self._zoneStatus = None self.zoneNumber = zoneNumber self.alertDevices = cfg['alertDevices'] self.name = cfg['name'] self.armAwayToggleSwitch = cfg['armAwayToggleSwitch'] self.armHomeToggleSwitch = cfg['armHomeToggleSwitch'] self.mainZone = cfg['mainZone'] self.canArmWithTrippedSensors = cfg['canArmWithTrippedSensors'] self.alarmTestMode = parent.alarmTestMode self.parent = weakref.ref(parent) # <= garbage-collector safe! self.log = logging.getLogger(u"{}.IdeAlarmZone.Zone.{}".format( LOG_PREFIX, self.zoneNumber)) self.sensors = [] for sensor in cfg['sensors']: self.sensors.append(IdeAlarmSensor(self, sensor)) self.armingModeItem = cfg['armingModeItem'] self.statusItem = cfg['statusItem'] self.openSections = self.countOpenSections() self.setArmingMode( getItemValue(self.armingModeItem, ARMINGMODE['DISARMED']) ) # Will also set the zone status to normal self.log.info( u"ideAlarm Zone {} initialized with {} open sensors".format( self.name.decode('utf8'), self.openSections))
def onSensorChange(self, sensor): ''' Called whenever an enabled sensor has tripped ON or OPEN ''' if self.getArmingMode() not in [ARMINGMODE['ARMED_HOME'], ARMINGMODE['ARMED_AWAY']] \ or self.getZoneStatus() not in [ZONESTATUS['NORMAL']] \ or (self.getArmingMode() == ARMINGMODE['ARMED_HOME'] and sensor.sensorClass == 'B') \ or getItemValue("Z{}_Exit_Timer".format(self.zoneNumber), scope.OFF) == scope.ON: self.log.info(u"{} was tripped, but we are ignoring it".format( sensor.name.decode('utf8'))) return self.setZoneStatus(ZONESTATUS['TRIPPED']) self.log.info(u"{} was tripped, starting entry timer".format( sensor.name.decode('utf8'))) postUpdateCheckFirst("Z{}_Entry_Timer".format(self.zoneNumber), scope.ON)
def greeting(): # To use this, you should set up astro.py as described # here https://github.com/OH-Jython-Scripters/Script%20Examples/astro.py # It will take care of updating the item 'V_TimeOfDay' for you # You can customize and/or translate these greetings in your configuration file. timeOfDay = getItemValue('V_TimeOfDay', TIMEOFDAY['DAY']) try: from configuration import timeofdayGreetings except ImportError: # No customized greetings found in configuration file. We use the following english greetings then timeofdayGreetings = { 0: 'Good night', 1: 'Good morning', 2: 'Good day', 3: 'Good evening' } if timeOfDay in timeofdayGreetings: return timeofdayGreetings[timeOfDay] else: return 'good day'
def weatherStationUploader(event): weatherStationUploader.log.setLevel(weatherStationUploader_configuration['logLevel']) global wu_second_count if (not weatherStationUploader_configuration['stationdata']['weather_upload']) \ or (weatherStationUploader_configuration['stationdata']['weather_upload'] and wu_second_count%weatherStationUploader_configuration['stationdata']['upload_frequency_seconds'] == 0): if weatherStationUploader_configuration['stationdata']['weather_upload']: weatherStationUploader.log.debug('Uploading data to Weather Underground') else: weatherStationUploader.log.debug('No data to will be upladed to Weather Underground') sdf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss") dateutc = sdf.print(DateTime.now((DateTimeZone.UTC))) tempf = None temp = None sensorName = getTheSensor('tempc', getLowest=True) if sensorName is not None: temp = Temp(getItemValue(sensorName, 0.0), 'c') # Outdoor temp, c - celsius, f - fahrenheit, k - kelvin tempf = str(round(temp.f, 1)) soiltempf = None sensorName = getTheSensor('soiltempc') if sensorName is not None: _temp = Temp(getItemValue(sensorName, 0.0), 'c') # Soil temp, c - celsius, f - fahrenheit, k - kelvin soiltempf = str(round(_temp.f, 1)) humidity = None sensorName = getTheSensor('humidity') if sensorName is not None: humidity = getItemValue(sensorName, 0.0) dewptf = None heatidxf = None if humidity is not None and temp is not None: dewptf = str(round(dew_point(temperature=temp, humidity=humidity).f, 1)) # calculate Dew Point heatidxf = str(round(heat_index(temperature=temp, humidity=humidity).f, 1)) # calculate Heat Index pressure = None sensorName = getTheSensor('pressurembar') if sensorName is not None: _mbar = getItemValue(sensorName, 0) if ((_mbar < 1070) and (_mbar > 920)): pressure = str(mbar_to_inches_mercury(_mbar)) rainin = None sensorName = getTheSensor('rainhour', never_assume_dead=True) if sensorName is not None: rainin = str(mm_to_inch(getItemValue(sensorName, 0.0))) dailyrainin = None sensorName = getTheSensor('raintoday', never_assume_dead=True) if sensorName is not None: dailyrainin = str(mm_to_inch(getItemValue(sensorName, 0.0))) soilmoisture = None sensorName = getTheSensor('soilmoisture') if sensorName is not None: soilmoisture = str(int(round(getItemValue(sensorName, 0.0) * 100 / 1023))) winddir = None sensorName = getTheSensor('winddir') if sensorName is not None: winddir = str(getItemValue(sensorName, 0)) windspeedmph = None sensorName = getTheSensor('windspeedms') if sensorName is not None: windspeedmph = str(ms_to_mph(getItemValue(sensorName, 0.0))) windgustmph = None sensorName = getTheSensor('windgustms') if sensorName is not None: windgustmph = str(ms_to_mph(getItemValue(sensorName, 0.0))) windgustdir = None sensorName = getTheSensor('windgustdir') if sensorName is not None: windgustdir = str(getItemValue(sensorName, 0)) windspdmph_avg2m = None sensorName = getTheSensor('windspeedms_avg2m') if sensorName is not None: windspdmph_avg2m = str(ms_to_mph(getItemValue(sensorName, 0.0))) winddir_avg2m = None sensorName = getTheSensor('winddir_avg2m') if sensorName is not None: winddir_avg2m = str(getItemValue(sensorName, 0)) windgustmph_10m = None sensorName = getTheSensor('windgustms_10m') if sensorName is not None: windgustmph_10m = str(ms_to_mph(getItemValue(sensorName, 0.0))) windgustdir_10m = None sensorName = getTheSensor('windgustdir_10m') if sensorName is not None: windgustdir_10m = str(getItemValue(sensorName, 0)) solarradiation = None sensorName = getTheSensor('solarradiation', getHighest=True) if sensorName is not None: solarradiation = str(lux_to_watts_m2(getItemValue(sensorName, 0))) # From http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol cmd = 'curl -s -G "' + WU_URL + '" ' \ + '--data-urlencode "action=updateraw" ' \ + ('--data-urlencode "realtime=1" ' if weatherStationUploader_configuration['stationdata']['rapid_fire_mode'] else '') \ + ('--data-urlencode "rtfreq='+str(weatherStationUploader_configuration['stationdata']['upload_frequency_seconds'])+'" ' if weatherStationUploader_configuration['stationdata']['rapid_fire_mode'] else '') \ + '--data-urlencode "ID='+weatherStationUploader_configuration['stationdata']['station_id']+'" ' \ + '--data-urlencode "PASSWORD='******'stationdata']['station_key']+'" ' \ + '--data-urlencode "dateutc='+dateutc+'" ' \ + '--data-urlencode "softwaretype=openHAB" ' weatherStationUploader.log.debug("") if weatherStationUploader_configuration['stationdata']['weather_upload']: weatherStationUploader.log.debug("Below is the weather data that we will send:") else: weatherStationUploader.log.debug("Below is the weather data that we would send (if weather_upload was enabled):") if tempf is not None: cmd += '--data-urlencode "tempf='+tempf+'" ' weatherStationUploader.log.debug("tempf: "+tempf) if humidity is not None: cmd += '--data-urlencode "humidity='+str(humidity)+'" ' weatherStationUploader.log.debug("humidity: "+str(humidity)) if dewptf is not None: cmd += '--data-urlencode "dewptf='+dewptf+'" ' weatherStationUploader.log.debug("dewptf: "+dewptf) if heatidxf is not None: cmd += '--data-urlencode "heatidxf='+heatidxf+'" ' weatherStationUploader.log.debug("heatidxf: "+heatidxf) if soiltempf is not None: cmd += '--data-urlencode "soiltempf='+soiltempf+'" ' weatherStationUploader.log.debug("soiltempf: "+soiltempf) if soilmoisture is not None: cmd += '--data-urlencode "soilmoisture='+soilmoisture+'" ' weatherStationUploader.log.debug("soilmoisture: "+soilmoisture) if pressure is not None: cmd += '--data-urlencode "baromin='+pressure+'" ' weatherStationUploader.log.debug("baromin: "+pressure) if rainin is not None: cmd += '--data-urlencode "rainin='+rainin+'" ' weatherStationUploader.log.debug("rainin: "+rainin) if dailyrainin is not None: cmd += '--data-urlencode "dailyrainin='+dailyrainin+'" ' weatherStationUploader.log.debug("dailyrainin: "+dailyrainin) if winddir is not None: cmd += '--data-urlencode "winddir='+winddir+'" ' weatherStationUploader.log.debug("winddir: "+winddir) if windspeedmph is not None: cmd += '--data-urlencode "windspeedmph='+windspeedmph+'" ' weatherStationUploader.log.debug("windspeedmph: "+windspeedmph) if windgustmph is not None: cmd += '--data-urlencode "windgustmph='+windgustmph+'" ' weatherStationUploader.log.debug("windgustmph: "+windgustmph) if windgustdir is not None: cmd += '--data-urlencode "windgustdir='+windgustdir+'" ' weatherStationUploader.log.debug("windgustdir: "+windgustdir) if windspdmph_avg2m is not None: cmd += '--data-urlencode "windspdmph_avg2m='+windspdmph_avg2m+'" ' weatherStationUploader.log.debug("windspdmph_avg2m: "+windspdmph_avg2m) if winddir_avg2m is not None: cmd += '--data-urlencode "winddir_avg2m='+winddir_avg2m+'" ' weatherStationUploader.log.debug("winddir_avg2m: "+winddir_avg2m) if windgustmph_10m is not None: cmd += '--data-urlencode "windgustmph_10m='+windgustmph_10m+'" ' weatherStationUploader.log.debug("windgustmph_10m: "+windgustmph_10m) if windgustdir_10m is not None: cmd += '--data-urlencode "windgustdir_10m='+windgustdir_10m+'" ' weatherStationUploader.log.debug("windgustdir_10m: "+windgustdir_10m) if solarradiation is not None: cmd += '--data-urlencode "solarradiation='+solarradiation+'" ' weatherStationUploader.log.debug("solarradiation: "+solarradiation) cmd += ' 1>/dev/null 2>&1 &' weatherStationUploader.log.debug("") if weatherStationUploader_configuration['stationdata']['weather_upload']: weatherStationUploader.log.debug("WeatherUpload version {}, performing an upload. (second count is: {})".format(__version__, wu_second_count)) weatherStationUploader.log.debug("cmd: {}".format(cmd)) os.system(cmd) else: weatherStationUploader.log.debug("WeatherUpload version {}, skipping upload. (second count is: {})".format(__version__, wu_second_count)) if (wu_second_count%weatherStationUploader_configuration['stationdata']['upload_frequency_seconds'] == 0): wu_second_count = 0 wu_second_count = wu_second_count + 10 # Corresponding to CronTrigger(EVERY_10_SECONDS)
def tts(ttsSay, ttsPrio=PRIO['MODERATE'], **keywords): ''' Text To Speak function. First argument is positional and mandatory. Remaining arguments are optionally keyword arguments. Examples: .. code-block:: tts("Hello") tts("Hello", PRIO['HIGH'], ttsRoom='Kitchen', ttsVol=42, ttsLang='en-GB', ttsVoice='Brian') Args: ttsSay (str): text to speak ttsPrio (str): (optional) priority as defined by PRIO (defaults to PRIO['MODERATE']) **keywords: ``ttsRoom`` (room to speak in), ``ttsVol`` (volume), ``ttsLang`` (language), ``ttsVoice`` (voice), ``ttsEngine`` (engine) Returns: bool: ``True``, if sound was sent, else ``False`` ''' log = logging.getLogger(LOG_PREFIX + ".community.sonos.speak") def getDefaultRoom(): # Search for the default room to speak in for the_key, the_value in sonos['rooms'].iteritems(): if the_value['defaultttsdevice']: return the_key return 'All' if getItemValue(customItemNames['allowTTSSwitch'], scope.ON) != scope.ON and ttsPrio <= PRIO['MODERATE']: log.info( u"[{}] is OFF and ttsPrio is too low to speak [{}] at this moment". format(customItemNames['allowTTSSwitch'].decode('utf8'), ttsSay)) return False ttsRoom = getDefaultRoom( ) if 'ttsRoom' not in keywords else keywords['ttsRoom'] ttsRooms = [] if ttsRoom == 'All' or ttsRoom is None: for the_key, the_value in sonos['rooms'].iteritems(): ttsRooms.append(sonos['rooms'][the_key]) log.debug(u"TTS room found: [{}]".format( sonos['rooms'][the_key]['name'].decode('utf8'))) else: sonosSpeaker = sonos['rooms'].get(ttsRoom, None) if sonosSpeaker is None: log.warn( u"Room [{}] wasn't found in the sonos rooms dictionary".format( ttsRoom.decode('utf8'))) return ttsRooms.append(sonosSpeaker) log.debug(u"TTS room found: [{}]".format( sonosSpeaker['name'].decode('utf8'))) for room in ttsRooms: ttsVol = None if 'ttsVol' not in keywords else keywords['ttsVol'] if not ttsVol or ttsVol >= 70: if ttsPrio == PRIO['LOW']: ttsVol = 30 elif ttsPrio == PRIO['MODERATE']: ttsVol = 40 elif ttsPrio == PRIO['HIGH']: ttsVol = 60 elif ttsPrio == PRIO['EMERGENCY']: ttsVol = 70 else: ttsVol = room['ttsvolume'] ttsLang = room['ttslang'] if 'ttsLang' not in keywords else keywords[ 'ttsLang'] ttsVoice = room[ 'ttsvoice'] if 'ttsVoice' not in keywords else keywords['ttsVoice'] ttsEngine = room[ 'ttsengine'] if 'ttsEngine' not in keywords else keywords[ 'ttsEngine'] #Voice.say(ttsSay, "{}:{}".format(ttsEngine, ttsVoice), room['audiosink']) Voice.say(ttsSay, "{}:{}".format(ttsEngine, ttsVoice), room['audiosink'], scope.PercentType(ttsVol)) # Volume is not well implemented log.info(u"TTS: Speaking [{}] in room [{}] at volume [{}]".format( ttsSay, room['name'].decode('utf8'), ttsVol)) return True
def playsound(fileName, ttsPrio=PRIO['MODERATE'], **keywords): ''' Play a sound mp3 file function. First argument is positional and mandatory. Remaining arguments are optionally keyword arguments. Example: playsound("Hello.mp3") Example: playsound("Hello.mp3", PRIO['HIGH'], room='Kitchen', volume=42) @param param1: Sound file name to play (positional argument) (files need to be put in the folder conf/sounds) @param param2: Priority as defined by PRIO. Defaults to PRIO['MODERATE'] @param room: Room to play in. Defaults to "All". @return: this is a description of what is returned ''' log = logging.getLogger(LOG_PREFIX + ".community.sonos.playsound") def getDefaultRoom(): # Search for the default room to speak in for the_key, the_value in sonos['rooms'].iteritems(): if the_value['defaultttsdevice']: return the_key return 'All' if getItemValue(customItemNames['allowTTSSwitch'], scope.ON) != scope.ON and ttsPrio <= PRIO['MODERATE']: log.info( "[{}] is OFF and ttsPrio is too low to play the sound [{}] at this moment" .format(customItemNames['allowTTSSwitch'], fileName)) return False room = getDefaultRoom() if 'room' not in keywords else keywords['room'] rooms = [] if room == 'All' or room is None: for the_key, the_value in sonos['rooms'].iteritems(): rooms.append(sonos['rooms'][the_key]) log.debug(u"Room found: [{}]".format( sonos['rooms'][the_key]['name'].decode('utf8'))) else: sonosSpeaker = sonos['rooms'].get(room, None) if sonosSpeaker is None: log.warn( u"Room [{}] wasn't found in the sonos rooms dictionary".format( room.decode('utf8'))) return rooms.append(sonosSpeaker) log.debug(u"Room found: [{}]".format( sonosSpeaker['name'].decode('utf8'))) for aRoom in rooms: ttsVol = None if 'ttsVol' not in keywords else keywords['ttsVol'] if not ttsVol or ttsVol >= 70: if ttsPrio == PRIO['LOW']: ttsVol = 30 elif ttsPrio == PRIO['MODERATE']: ttsVol = 40 elif ttsPrio == PRIO['HIGH']: ttsVol = 60 elif ttsPrio == PRIO['EMERGENCY']: ttsVol = 70 else: ttsVol = aRoom['ttsvolume'] Audio.playSound(aRoom['audiosink'], fileName) log.info(u"playSound: Playing [{}] in room [{}] at volume [{}]".format( fileName.decode('utf8'), aRoom['name'].decode('utf8'), ttsVol)) return True
def __call__(self, event): log.debug("rule {} triggered by {}, state {}".format( self.__class__.__name__, event.itemName, event.itemState)) events.postUpdate(self.item2.name, str(2 * getItemValue(self.item1.name, 0.1)))