예제 #1
0
async def test_as_number_coercion(opp):
    """Test state_as_number with number."""
    for _state in ("0", "0.0", 0, 0.0):
        assert state.state_as_number(ha.State("domain.test", _state,
                                              {})) == 0.0
    for _state in ("1", "1.0", 1, 1.0):
        assert state.state_as_number(ha.State("domain.test", _state,
                                              {})) == 1.0
예제 #2
0
async def test_as_number_states(opp):
    """Test state_as_number with states."""
    zero_states = (
        STATE_OFF,
        STATE_CLOSED,
        STATE_UNLOCKED,
        STATE_BELOW_HORIZON,
        STATE_NOT_HOME,
    )
    one_states = (STATE_ON, STATE_OPEN, STATE_LOCKED, STATE_ABOVE_HORIZON,
                  STATE_HOME)
    for _state in zero_states:
        assert state.state_as_number(ha.State("domain.test", _state, {})) == 0
    for _state in one_states:
        assert state.state_as_number(ha.State("domain.test", _state, {})) == 1
예제 #3
0
    def state_changed_listener(event):
        """Listen for new messages on the bus and sends them to Datadog."""
        state = event.data.get("new_state")

        if state is None or state.state == STATE_UNKNOWN:
            return

        states = dict(state.attributes)
        metric = f"{prefix}.{state.domain}"
        tags = [f"entity:{state.entity_id}"]

        for key, value in states.items():
            if isinstance(value, (float, int)):
                attribute = f"{metric}.{key.replace(' ', '_')}"
                value = int(value) if isinstance(value, bool) else value
                statsd.gauge(attribute,
                             value,
                             sample_rate=sample_rate,
                             tags=tags)

                _LOGGER.debug("Sent metric %s: %s (tags: %s)", attribute,
                              value, tags)

        try:
            value = state_helper.state_as_number(state)
        except ValueError:
            _LOGGER.debug("Error sending %s: %s (tags: %s)", metric,
                          state.state, tags)
            return

        statsd.gauge(metric, value, sample_rate=sample_rate, tags=tags)

        _LOGGER.debug("Sent metric %s: %s (tags: %s)", metric, value, tags)
예제 #4
0
    def update_emoncms(time):
        """Send whitelisted entities states regularly to Emoncms."""
        payload_dict = {}

        for entity_id in whitelist:
            state = opp.states.get(entity_id)

            if state is None or state.state in (STATE_UNKNOWN, "",
                                                STATE_UNAVAILABLE):
                continue

            try:
                payload_dict[entity_id] = state_helper.state_as_number(state)
            except ValueError:
                continue

        if payload_dict:
            payload = "{%s}" % ",".join(f"{key}:{val}"
                                        for key, val in payload_dict.items())

            send_data(
                conf.get(CONF_URL),
                conf.get(CONF_API_KEY),
                str(conf.get(CONF_INPUTNODE)),
                payload,
            )

        track_point_in_time(
            opp, update_emoncms,
            time + timedelta(seconds=conf.get(CONF_SCAN_INTERVAL)))
예제 #5
0
 def state_as_number(state):
     """Return a state casted to a float."""
     try:
         value = state_helper.state_as_number(state)
     except ValueError:
         _LOGGER.debug("Could not convert %s to float", state)
         value = 0
     return value
예제 #6
0
    def event_to_metrics(event, float_keys, string_keys):
        """Add an event to the outgoing Zabbix list."""
        state = event.data.get("new_state")
        if state is None or state.state in (STATE_UNKNOWN, "",
                                            STATE_UNAVAILABLE):
            return

        entity_id = state.entity_id
        if not entities_filter(entity_id):
            return

        floats = {}
        strings = {}
        try:
            _state_as_value = float(state.state)
            floats[entity_id] = _state_as_value
        except ValueError:
            try:
                _state_as_value = float(state_helper.state_as_number(state))
                floats[entity_id] = _state_as_value
            except ValueError:
                strings[entity_id] = state.state

        for key, value in state.attributes.items():
            # For each value we try to cast it as float
            # But if we can not do it we store the value
            # as string
            attribute_id = f"{entity_id}/{key}"
            try:
                float_value = float(value)
            except (ValueError, TypeError):
                float_value = None
            if float_value is None or not math.isfinite(float_value):
                strings[attribute_id] = str(value)
            else:
                floats[attribute_id] = float_value

        metrics = []
        float_keys_count = len(float_keys)
        float_keys.update(floats)
        if len(float_keys) != float_keys_count:
            floats_discovery = []
            for float_key in float_keys:
                floats_discovery.append({"{#KEY}": float_key})
            metric = ZabbixMetric(
                publish_states_host,
                "openpeerpower.floats_discovery",
                json.dumps(floats_discovery),
            )
            metrics.append(metric)
        for key, value in floats.items():
            metric = ZabbixMetric(publish_states_host,
                                  f"openpeerpower.float[{key}]", value)
            metrics.append(metric)

        string_keys.update(strings)
        return metrics
예제 #7
0
    def event_to_json(event):
        """Add an event to the outgoing list."""
        state = event.data.get("new_state")
        if (state is None
                or state.state in (STATE_UNKNOWN, "", STATE_UNAVAILABLE)
                or state.entity_id in exclude_e or state.domain in exclude_d):
            return

        if (include_e and state.entity_id not in include_e) or (
                include_d and state.domain not in include_d):
            return

        try:
            _state_as_value = float(state.state)
        except ValueError:
            _state_as_value = None

        if _state_as_value is None:
            try:
                _state_as_value = float(state_helper.state_as_number(state))
            except ValueError:
                _state_as_value = None

        out_event = {
            "tags": {
                "domain": state.domain,
                "entity_id": state.object_id
            },
            "time": event.time_fired.isoformat(),
            "fields": {
                "state": state.state
            },
        }
        if _state_as_value is not None:
            out_event["fields"]["state_value"] = _state_as_value

        for key, value in state.attributes.items():
            if key != "unit_of_measurement":
                # If the key is already in fields
                if key in out_event["fields"]:
                    key = f"{key}_"
                # For each value we try to cast it as float
                # But if we can not do it we store the value
                # as string
                try:
                    out_event["fields"][key] = float(value)
                except (ValueError, TypeError):
                    out_event["fields"][key] = str(value)

        return out_event
예제 #8
0
    def dweet_event_listener(event):
        """Listen for new messages on the bus and sends them to Dweet.io."""
        state = event.data.get("new_state")
        if (
            state is None
            or state.state in (STATE_UNKNOWN, "")
            or state.entity_id not in whitelist
        ):
            return

        try:
            _state = state_helper.state_as_number(state)
        except ValueError:
            _state = state.state

        json_body[state.attributes.get(ATTR_FRIENDLY_NAME)] = _state

        send_data(name, json_body)
예제 #9
0
 def thingspeak_listener(entity_id, old_state, new_state):
     """Listen for new events and send them to Thingspeak."""
     if new_state is None or new_state.state in (
             STATE_UNKNOWN,
             "",
             STATE_UNAVAILABLE,
     ):
         return
     try:
         if new_state.entity_id != entity:
             return
         _state = state_helper.state_as_number(new_state)
     except ValueError:
         return
     try:
         channel.update({"field1": _state})
     except RequestException:
         _LOGGER.error("Error while sending value '%s' to Thingspeak",
                       _state)
예제 #10
0
 def _report_attributes(self, entity_id, new_state):
     """Report the attributes."""
     now = time.time()
     things = dict(new_state.attributes)
     with suppress(ValueError):
         things["state"] = state.state_as_number(new_state)
     lines = [
         "%s.%s.%s %f %i" %
         (self._prefix, entity_id, key.replace(" ", "_"), value, now)
         for key, value in things.items()
         if isinstance(value, (float, int))
     ]
     if not lines:
         return
     _LOGGER.debug("Sending to graphite: %s", lines)
     try:
         self._send_to_graphite("\n".join(lines))
     except socket.gaierror:
         _LOGGER.error("Unable to connect to host %s", self._host)
     except OSError:
         _LOGGER.exception("Failed to send data to graphite")
예제 #11
0
 def logentries_event_listener(event):
     """Listen for new messages on the bus and sends them to Logentries."""
     state = event.data.get("new_state")
     if state is None:
         return
     try:
         _state = state_helper.state_as_number(state)
     except ValueError:
         _state = state.state
     json_body = [{
         "domain": state.domain,
         "entity_id": state.object_id,
         "attributes": dict(state.attributes),
         "time": str(event.time_fired),
         "value": _state,
     }]
     try:
         payload = {"host": le_wh, "event": json_body}
         requests.post(le_wh, data=json.dumps(payload), timeout=10)
     except requests.exceptions.RequestException as error:
         _LOGGER.exception("Error sending to Logentries: %s", error)
예제 #12
0
    def statsd_event_listener(event):
        """Listen for new messages on the bus and sends them to StatsD."""
        state = event.data.get("new_state")

        if state is None:
            return

        try:
            if value_mapping and state.state in value_mapping:
                _state = float(value_mapping[state.state])
            else:
                _state = state_helper.state_as_number(state)
        except ValueError:
            # Set the state to none and continue for any numeric attributes.
            _state = None

        states = dict(state.attributes)

        _LOGGER.debug("Sending %s", state.entity_id)

        if show_attribute_flag is True:
            if isinstance(_state, (float, int)):
                statsd_client.gauge("%s.state" % state.entity_id, _state,
                                    sample_rate)

            # Send attribute values
            for key, value in states.items():
                if isinstance(value, (float, int)):
                    stat = "{}.{}".format(state.entity_id,
                                          key.replace(" ", "_"))
                    statsd_client.gauge(stat, value, sample_rate)

        else:
            if isinstance(_state, (float, int)):
                statsd_client.gauge(state.entity_id, _state, sample_rate)

        # Increment the count
        statsd_client.incr(state.entity_id, rate=sample_rate)
예제 #13
0
async def test_as_number_invalid_cases(opp):
    """Test state_as_number with invalid cases."""
    for _state in ("", "foo", "foo.bar", None, False, True, object, object()):
        with pytest.raises(ValueError):
            state.state_as_number(ha.State("domain.test", _state, {}))
예제 #14
0
    def event_to_json(event: dict) -> str:
        """Convert event into json in format Influx expects."""
        state = event.data.get(EVENT_NEW_STATE)
        if (
            state is None
            or state.state in (STATE_UNKNOWN, "", STATE_UNAVAILABLE)
            or not entity_filter(state.entity_id)
        ):
            return

        try:
            _include_state = _include_value = False

            _state_as_value = float(state.state)
            _include_value = True
        except ValueError:
            try:
                _state_as_value = float(state_helper.state_as_number(state))
                _include_state = _include_value = True
            except ValueError:
                _include_state = True

        include_uom = True
        include_dc = True
        entity_config = component_config.get(state.entity_id)
        measurement = entity_config.get(CONF_OVERRIDE_MEASUREMENT)
        if measurement in (None, ""):
            if override_measurement:
                measurement = override_measurement
            else:
                if measurement_attr == "entity_id":
                    measurement = state.entity_id
                elif measurement_attr == "domain__device_class":
                    device_class = state.attributes.get("device_class")
                    if device_class is None:
                        # This entity doesn't have a device_class set, use only domain
                        measurement = state.domain
                    else:
                        measurement = f"{state.domain}__{device_class}"
                        include_dc = False
                else:
                    measurement = state.attributes.get(measurement_attr)
                if measurement in (None, ""):
                    if default_measurement:
                        measurement = default_measurement
                    else:
                        measurement = state.entity_id
                else:
                    include_uom = measurement_attr != "unit_of_measurement"

        json = {
            INFLUX_CONF_MEASUREMENT: measurement,
            INFLUX_CONF_TAGS: {
                CONF_DOMAIN: state.domain,
                CONF_ENTITY_ID: state.object_id,
            },
            INFLUX_CONF_TIME: event.time_fired,
            INFLUX_CONF_FIELDS: {},
        }
        if _include_state:
            json[INFLUX_CONF_FIELDS][INFLUX_CONF_STATE] = state.state
        if _include_value:
            json[INFLUX_CONF_FIELDS][INFLUX_CONF_VALUE] = _state_as_value

        ignore_attributes = set(entity_config.get(CONF_IGNORE_ATTRIBUTES, []))
        ignore_attributes.update(global_ignore_attributes)
        for key, value in state.attributes.items():
            if key in tags_attributes:
                json[INFLUX_CONF_TAGS][key] = value
            elif (
                (key != CONF_UNIT_OF_MEASUREMENT or include_uom)
                and (key != "device_class" or include_dc)
                and key not in ignore_attributes
            ):
                # If the key is already in fields
                if key in json[INFLUX_CONF_FIELDS]:
                    key = f"{key}_"
                # Prevent column data errors in influxDB.
                # For each value we try to cast it as float
                # But if we can not do it we store the value
                # as string add "_str" postfix to the field key
                try:
                    json[INFLUX_CONF_FIELDS][key] = float(value)
                except (ValueError, TypeError):
                    new_key = f"{key}_str"
                    new_value = str(value)
                    json[INFLUX_CONF_FIELDS][new_key] = new_value

                    if RE_DIGIT_TAIL.match(new_value):
                        json[INFLUX_CONF_FIELDS][key] = float(
                            RE_DECIMAL.sub("", new_value)
                        )

                # Infinity and NaN are not valid floats in InfluxDB
                with suppress(KeyError, TypeError):
                    if not math.isfinite(json[INFLUX_CONF_FIELDS][key]):
                        del json[INFLUX_CONF_FIELDS][key]

        json[INFLUX_CONF_TAGS].update(tags)

        return json