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.

            def isSensorAlive(sName):
                if getLastUpdate(PersistenceExtensions,
                                 ir.getItem(sName)).isAfter(
                                     DateTime.now().minusMinutes(
                                         sensor_dead_after_mins)):
                    return True
                else:
                    self.log.warning('Sensor device ' + unicode(sName) +
                                     ' has not reported since: ' + str(
                                         getLastUpdate(PersistenceExtensions,
                                                       ir.getItem(sName))))
                    return False

            sensorName = None
            if lbl in self.config.wunderground[
                    'sensors'] and self.config.wunderground['sensors'][
                        lbl] is not None:
                tSens = self.config.wunderground['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:
                self.log.debug("Device used for " + unicode(lbl) + ": " +
                               sensorName)
            return sensorName
Exemple #2
0
    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(LOG_PREFIX + '.IdeAlarmZone.' +
                                     self.name.decode('utf8'))
        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('ideAlarm Zone ' + self.name.decode('utf8') +
                      ' initialized with ' + str(self.openSections) +
                      ' open sensors')
Exemple #3
0
    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'+str(self.zoneNumber)+'_Exit_Timer', OFF) == ON:
            self.log.info(
                sensor.name.decode('utf-8') +
                ' was tripped, but we are ignoring it')
            return

        if (not sensor.armWarn):
            self.setZoneStatus(ZONESTATUS['TRIPPED'])
            self.log.info(
                sensor.name.decode('utf-8') +
                ' was tripped, starting entry timer')
            postUpdateCheckFirst('Z' + str(self.zoneNumber) + '_Entry_Timer',
                                 ON)
        else:
            self.onEntryTimer()
            self.log.info(
                sensor.name.decode('utf-8') +
                ' was tripped, armWarn is set to True, go directly to the ALERT Mode'
            )
Exemple #4
0
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
    '''
    module_name = 'playsound'
    log = logging.getLogger(LOG_PREFIX+'.'+module_name)
    log.setLevel(logging.INFO)

    def getDefaultRoom():
        # Search for the default room to speak in
        for the_key, the_value in config.sonos['rooms'].iteritems():
            if the_value['defaultttsdevice']:
                return the_key
        return 'All'

    if ((getItemValue(config.customItemNames['allowTTSSwitch'], ON) != ON) and (ttsPrio <= PRIO['MODERATE'])):
        log.info(unicode(config.customItemNames['allowTTSSwitch']) + " is OFF and ttsPrio is to low to play sound \'" + fileName + "\' at this moment.")
        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 config.sonos['rooms'].iteritems():
            rooms.append(config.sonos['rooms'][the_key])
            log.debug('Room found: ' + config.sonos['rooms'][the_key]['name'])
    else:
        sonosSpeaker = config.sonos['rooms'].get(room, None)
        if sonosSpeaker is None:
            log.error("Room "+room+" wasn't found in the sonos rooms dictionary")
            return
        rooms.append(sonosSpeaker)
        log.debug('Room found: ' + sonosSpeaker['name'])

    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("playSound: \'" + fileName + "\'" + ' in room: \'' + aRoom['name'] + '\' at volume: \'' + str(ttsVol) + '\'.')

    return True
    def execute(self, modules, inputs):

        SCRIPT_VERSION = '2.3.1'
        WU_URL = "http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php"

        def ms_to_mph(input_speed):
            # convert input_speed from meter per second to miles per hour
            return round(input_speed / 0.44704, 2)

        def mm_to_inch(mm):
            # convert mm to inches
            return round(mm / 25.4, 2)

        def mbar_to_inches_mercury(input_pressure):
            # convert mbar to inches mercury
            return round(input_pressure * 0.02953, 2)

        def lux_to_watts_m2(lux):
            # Convert lux [lx] to watt/m² (at 555 nm)
            # Should typically be around 800-900 watt/m² at mid summer full sun diation at 13.00 h
            # return int(round(float(lux) * 0.01464128843))
            return int(round(float(lux) * 0.015454545))

        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.

            def isSensorAlive(sName):
                if getLastUpdate(PersistenceExtensions,
                                 ir.getItem(sName)).isAfter(
                                     DateTime.now().minusMinutes(
                                         sensor_dead_after_mins)):
                    return True
                else:
                    self.log.warning('Sensor device ' + unicode(sName) +
                                     ' has not reported since: ' + str(
                                         getLastUpdate(PersistenceExtensions,
                                                       ir.getItem(sName))))
                    return False

            sensorName = None
            if lbl in self.config.wunderground[
                    'sensors'] and self.config.wunderground['sensors'][
                        lbl] is not None:
                tSens = self.config.wunderground['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:
                self.log.debug("Device used for " + unicode(lbl) + ": " +
                               sensorName)
            return sensorName

        self.log.setLevel(self.config.wunderground['logLevel'])

        global wu_loop_count
        sensor_dead_after_mins = self.config.wunderground[
            'sensor_dead_after_mins']  # The time after which a sensor is presumed to be dead
        if (not self.config.wunderground['stationdata']['weather_upload']) \
        or (self.config.wunderground['stationdata']['weather_upload'] and wu_loop_count%self.config.wunderground['stationdata']['upload_frequency'] == 0):
            if self.config.wunderground['stationdata']['weather_upload']:
                self.log.debug('Uploading data to Weather Underground')
            else:
                self.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 "ID='+self.config.wunderground['stationdata']['station_id']+'" ' \
                + '--data-urlencode "PASSWORD='******'stationdata']['station_key']+'" ' \
                + '--data-urlencode "dateutc='+dateutc+'" ' \
                + '--data-urlencode "softwaretype=openHAB" '
            self.log.debug("")

            if self.config.wunderground['stationdata']['weather_upload']:
                self.log.debug("Below is the weather data that we will send:")
            else:
                self.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 + '" '
                self.log.debug("tempf: " + tempf)
            if humidity is not None:
                cmd += '--data-urlencode "humidity=' + str(humidity) + '" '
                self.log.debug("humidity: " + str(humidity))
            if dewptf is not None:
                cmd += '--data-urlencode "dewptf=' + dewptf + '" '
                self.log.debug("dewptf: " + dewptf)
            if heatidxf is not None:
                cmd += '--data-urlencode "heatidxf=' + heatidxf + '" '
                self.log.debug("heatidxf: " + heatidxf)
            if soiltempf is not None:
                cmd += '--data-urlencode "soiltempf=' + soiltempf + '" '
                self.log.debug("soiltempf: " + soiltempf)
            if soilmoisture is not None:
                cmd += '--data-urlencode "soilmoisture=' + soilmoisture + '" '
                self.log.debug("soilmoisture: " + soilmoisture)
            if pressure is not None:
                cmd += '--data-urlencode "baromin=' + pressure + '" '
                self.log.debug("baromin: " + pressure)
            if rainin is not None:
                cmd += '--data-urlencode "rainin=' + rainin + '" '
                self.log.debug("rainin: " + rainin)
            if dailyrainin is not None:
                cmd += '--data-urlencode "dailyrainin=' + dailyrainin + '" '
                self.log.debug("dailyrainin: " + dailyrainin)
            if winddir is not None:
                cmd += '--data-urlencode "winddir=' + winddir + '" '
                self.log.debug("winddir: " + winddir)
            if windspeedmph is not None:
                cmd += '--data-urlencode "windspeedmph=' + windspeedmph + '" '
                self.log.debug("windspeedmph: " + windspeedmph)
            if windgustmph is not None:
                cmd += '--data-urlencode "windgustmph=' + windgustmph + '" '
                self.log.debug("windgustmph: " + windgustmph)
            if windgustdir is not None:
                cmd += '--data-urlencode "windgustdir=' + windgustdir + '" '
                self.log.debug("windgustdir: " + windgustdir)
            if windspdmph_avg2m is not None:
                cmd += '--data-urlencode "windspdmph_avg2m=' + windspdmph_avg2m + '" '
                self.log.debug("windspdmph_avg2m: " + windspdmph_avg2m)
            if winddir_avg2m is not None:
                cmd += '--data-urlencode "winddir_avg2m=' + winddir_avg2m + '" '
                self.log.debug("winddir_avg2m: " + winddir_avg2m)
            if windgustmph_10m is not None:
                cmd += '--data-urlencode "windgustmph_10m=' + windgustmph_10m + '" '
                self.log.debug("windgustmph_10m: " + windgustmph_10m)
            if windgustdir_10m is not None:
                cmd += '--data-urlencode "windgustdir_10m=' + windgustdir_10m + '" '
                self.log.debug("windgustdir_10m: " + windgustdir_10m)
            if solarradiation is not None:
                cmd += '--data-urlencode "solarradiation=' + solarradiation + '" '
                self.log.debug("solarradiation: " + solarradiation)
            cmd += ' 1>/dev/null 2>&1 &'
            self.log.debug("")

            if self.config.wunderground['stationdata']['weather_upload']:
                self.log.debug('WeatherUpload version ' + SCRIPT_VERSION +
                               ', performing an upload. (loop count is: ' +
                               str(wu_loop_count) + ')')
                self.log.debug('cmd: ' + cmd)
                os.system(cmd)
        else:
            self.log.debug('WeatherUpload version ' + SCRIPT_VERSION +
                           ', skipping upload. (loop count is: ' +
                           str(wu_loop_count) + ')')

        if (wu_loop_count %
                self.config.wunderground['stationdata']['upload_frequency'] ==
                0):
            wu_loop_count = 0
        wu_loop_count = wu_loop_count + 1
Exemple #6
0
def tts(ttsSay, ttsPrio=PRIO['MODERATE'], **keywords):
    '''
    Text To Speak function. First argument is positional and mandatory.
    Remaining arguments are optionally keyword arguments.
    Example: tts("Hello")
    Example: tts("Hello", PRIO['HIGH'], ttsRoom='Kitchen', ttsVol=42, ttsLang='en-GB', ttsVoice='Brian')
    @param param1: Text to speak (positional argument)
    @param param2: Priority as defined by PRIO. Defaults to PRIO['MODERATE']
    @param ttsRoom: Room to speak in
    @return: this is a description of what is returned
    '''
    module_name = 'speak'
    log = logging.getLogger(LOG_PREFIX + '.' + module_name)
    log.setLevel(logging.INFO)

    def getDefaultRoom():
        # Search for the default room to speak in
        for the_key, the_value in config.sonos['rooms'].iteritems():
            if the_value['defaultttsdevice']:
                return the_key
        return 'All'

    if ((getItemValue('Sonos_Allow_TTS_And_Sounds', ON) != ON)
            and (ttsPrio <= PRIO['MODERATE'])):
        log.info(
            "Item Sonos_Allow_TTS_And_Sounds is OFF and ttsPrio is to low to speak \'"
            + ttsSay + "\' at this moment.")
        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 config.sonos['rooms'].iteritems():
            ttsRooms.append(config.sonos['rooms'][the_key])
            log.debug('TTS room found: ' +
                      config.sonos['rooms'][the_key]['name'])
    else:
        sonosSpeaker = config.sonos['rooms'].get(ttsRoom, None)
        if sonosSpeaker is None:
            log.error("Room " + ttsRoom +
                      " wasn't found in the sonos rooms dictionary")
            return
        ttsRooms.append(sonosSpeaker)
        log.debug('TTS room found: ' + sonosSpeaker['name'])

    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, ttsEngine + ':' + ttsVoice, room['audiosink'], PercentType(10)) # Notification sound volume doesn't seem to be supported
        Voice.say(ttsSay, ttsEngine + ':' + ttsVoice, room['audiosink'])
        log.info("TTS: Speaking \'" + ttsSay + "\'" + ' in room: \'' +
                 room['name'] + '\' at volume: \'' + str(ttsVol) + '\'.')

    return True