示例#1
0
def main():
    if config is None:
        print("COULD NOT DETECT CONFIG FILE")
        return


    home = Home()
    home.set_auth_token(config.auth_token)
    home.init(config.access_point)
    print("Downloading configuration")
    home.get_current_state()
    if not os.path.exists("./img/"):
        os.makedirs("./img/")

    print("Generating QRCodes")
    for d in home.devices:
        img = qrcode.make(d.id)
        img.save("./img/{}.png".format(d.id))

    print("Creating website")
    templatePath = os.path.join(os.path.dirname(__file__), 'qrcodes_template.html')
    template = None
    tableText = ""
    with open(templatePath, "r") as t:
        template = t.read()
    for g in home.groups:
        if not isinstance(g, MetaGroup):
            continue;
        for d in g.devices:
            tableText = tableText + "<tr><td>{}</td><td>{}</td><td>{}</td><td>{}</td><td><img src=\"img/{}.png\"></td></tr>\n".format(g.label, d.label, d.id, d.modelType, d.id)
    result = template.replace("##QRROWS##", tableText)
    with codecs.open("qrcodes.html", "w", "UTF-8") as f:
        f.write(result)

    print("Finished")
class HomematicIpSource(Source):
    """
    Collects sensor data from homematic IP.
    Requires pip install homematicip.
    See https://homematicip-rest-api.readthedocs.io/en/latest/gettingstarted.html#installation for more details
    """
    def __init__(self, config):
        super().__init__(config)
        self._auth_token = config['authToken']
        self._access_point = config['accessPoint']
        self._home = None

    def setup(self, global_conf):
        super().setup(global_conf)
        self._home = Home()
        self._home.set_auth_token(self._auth_token)
        self._home.init(self._access_point)

    def _probe(self) -> Optional[ValueSet] or List[ValueSet]:
        values = ValueSet(labels=['room'])
        self._home.get_current_state()
        for group in self._home.groups:
            if group.groupType != 'META':
                continue

            room_name = self._escape_labels(group.label)
            for device in group.devices:
                if isinstance(device, TemperatureHumiditySensorDisplay):
                    # device.lastStatusUpdate
                    temp_target = device.setPointTemperature
                    temp = device.actualTemperature
                    humidity = device.humidity
                    values.add(
                        Value(temp_target,
                              label_values=[room_name],
                              name='temperature_target'))
                    values.add(
                        Value(temp,
                              label_values=[room_name],
                              name='temperature'))
                    values.add(
                        Value(humidity,
                              label_values=[room_name],
                              name='humidity'))

        return values

    @staticmethod
    def _escape_labels(label: str) -> str:
        label = label.lower().replace('ä', 'ae') \
            .replace('ü', 'ue') \
            .replace('ö', 'oe') \
            .replace(' ', '_')
        return label
def setup(hass, config):
    """Set up the HomematicIP component."""
    # pylint: disable=import-error, no-name-in-module
    from homematicip.home import Home

    hass.data.setdefault(DOMAIN, {})
    homes = hass.data[DOMAIN]
    accesspoints = config.get(DOMAIN, [])

    def _update_event(events):
        """Handle incoming HomeMaticIP events."""
        for event in events:
            etype = event['eventType']
            edata = event['data']
            if etype == 'DEVICE_CHANGED':
                dispatcher_send(hass, EVENT_DEVICE_CHANGED, edata.id)
            elif etype == 'GROUP_CHANGED':
                dispatcher_send(hass, EVENT_GROUP_CHANGED, edata.id)
            elif etype == 'HOME_CHANGED':
                dispatcher_send(hass, EVENT_HOME_CHANGED, edata.id)
            elif etype == 'JOURNAL_CHANGED':
                dispatcher_send(hass, EVENT_SECURITY_CHANGED, edata.id)
        return True

    for device in accesspoints:
        name = device.get(CONF_NAME)
        accesspoint = device.get(CONF_ACCESSPOINT)
        authtoken = device.get(CONF_AUTHTOKEN)

        home = Home()
        if name.lower() == 'none':
            name = ''
        home.label = name
        try:
            home.set_auth_token(authtoken)
            home.init(accesspoint)
            if home.get_current_state():
                _LOGGER.info("Connection to HMIP established")
            else:
                _LOGGER.warning("Connection to HMIP could not be established")
                return False
        except timeout:
            _LOGGER.warning("Connection to HMIP could not be established")
            return False
        homes[home.id] = home
        home.onEvent += _update_event
        home.enable_events()
        _LOGGER.info('HUB name: %s, id: %s', home.label, home.id)

        for component in ['sensor']:
            load_platform(hass, component, DOMAIN, {'homeid': home.id}, config)

    return True
def setup(hass, config):
    """Set up the HomematicIP component."""
    # pylint: disable=import-error, no-name-in-module
    from homematicip.home import Home

    hass.data.setdefault(DOMAIN, {})
    homes = hass.data[DOMAIN]
    accesspoints = config.get(DOMAIN, [])

    def _update_event(events):
        """Handle incoming HomeMaticIP events."""
        for event in events:
            etype = event['eventType']
            edata = event['data']
            if etype == 'DEVICE_CHANGED':
                dispatcher_send(hass, EVENT_DEVICE_CHANGED, edata.id)
            elif etype == 'GROUP_CHANGED':
                dispatcher_send(hass, EVENT_GROUP_CHANGED, edata.id)
            elif etype == 'HOME_CHANGED':
                dispatcher_send(hass, EVENT_HOME_CHANGED, edata.id)
            elif etype == 'JOURNAL_CHANGED':
                dispatcher_send(hass, EVENT_SECURITY_CHANGED, edata.id)
        return True

    for device in accesspoints:
        name = device.get(CONF_NAME)
        accesspoint = device.get(CONF_ACCESSPOINT)
        authtoken = device.get(CONF_AUTHTOKEN)

        home = Home()
        if name.lower() == 'none':
            name = ''
        home.label = name
        try:
            home.set_auth_token(authtoken)
            home.init(accesspoint)
            if home.get_current_state():
                _LOGGER.info("Connection to HMIP established")
            else:
                _LOGGER.warning("Connection to HMIP could not be established")
                return False
        except timeout:
            _LOGGER.warning("Connection to HMIP could not be established")
            return False
        homes[home.id] = home
        home.onEvent += _update_event
        home.enable_events()
        _LOGGER.info('HUB name: %s, id: %s', home.label, home.id)

        for component in ['sensor']:
            load_platform(hass, component, DOMAIN, {'homeid': home.id}, config)

    return True
示例#5
0
def main():
    if config is None:
        print("COULD NOT DETECT CONFIG FILE")
        return

    home = Home()
    home.set_auth_token(config.auth_token)
    home.init(config.access_point)

    home.get_current_state()

    print("current AP Version: {}".format(home.currentAPVersion))
def fake_home(fake_cloud):
    home = Home()
    with no_ssl_verification():
        lookup_url = "{}/getHost".format(fake_cloud.url)
        #    home.download_configuration = fake_home_download_configuration
        home._connection = Connection()
        home._fake_cloud = fake_cloud
        home.set_auth_token(
            "8A45BAA53BE37E3FCA58E9976EFA4C497DAFE55DB997DB9FD685236E5E63ED7DE"
        )
        home._connection.init(accesspoint_id="3014F711A000000BAD0C0DED",
                              lookup_url=lookup_url)
        home.get_current_state()
    return home
示例#7
0
def init(c=[]):
    global config
    global metrics
    global h

    config = c

    h = Home()
    h.set_auth_token(config["authtoken"])
    h.init(config["accesspointid"])

    metrics = {}
    metrics['heating'] = {}
    metrics['heating']['setPointTemperature'] = Gauge(
        'homematicip_heating_setpointtemperature_celsius',
        'Homematic IP setpoint temperature of a room', ['id', 'room'])
    metrics['heating']['actualTemperature'] = Gauge(
        'homematicip_heating_actualtemperature_celsius',
        'Homematic IP actual temperature of a room', ['id', 'room'])
    metrics['heating']['boostmode'] = Gauge(
        'homematicip_heating_boostmode',
        'Homematic IP wether boost mode is on or off', ['id', 'room'])
    metrics['heating']['ecomode'] = Gauge(
        'homematicip_heating_ecomode',
        'Homematic IP wether eco mode is on or off', ['id', 'room'])
    metrics['heating']['partymode'] = Gauge(
        'homematicip_heating_partymode',
        'Homematic IP wether party mode is on or off', ['id', 'room'])
    metrics['heating']['humidity'] = Gauge(
        'homematicip_heating_humidity_percent',
        'Homematic IP current relative humidity in percent', ['id', 'room'])

    metrics['heating']['lowbattery'] = Gauge(
        'homematicip_heating_lowbattery',
        'Homematic IP wether the battery is low or not',
        ['id', 'name', 'room', 'devicetype', 'modeltype'])
    metrics['heating']['reachable'] = Gauge(
        'homematicip_heating_reachable',
        'Homematic IP wether the device is reachable or not',
        ['id', 'name', 'room', 'devicetype', 'modeltype'])

    metrics['heating']['valveposition'] = Gauge(
        'homematicip_heating_valveposition',
        'Homematic IP position of the valve',
        ['id', 'name', 'room', 'modeltype'])
    metrics['heating']['windowState'] = Gauge(
        'homematicip_heating_windowstate',
        'Homematic IP wether the window is open or closed',
        ['id', 'name', 'room', 'modeltype'])
示例#8
0
def main():
    config = homematicip.find_and_load_config_file()
    home = Home()
    home.set_auth_token(config.auth_token)
    home.init(config.access_point)

    c = lambda: None
    c.__dict__ = config.raw_config['TB']
    tb = ThingsboardConnection(c)

    home.get_current_state()
    for g in home.groups:
        if g.groupType == "META":
            for d in g.devices:
                try:
                    x = tb.getOrCreateDevice(g, d)
                    x.updateTelemetryFromHmIP(g, d)
                except:
                    print("Error updating telemetry from '%s' (%s)" %
                          (d.label, d.id))
示例#9
0
def main():
    if config is None:
        print("COULD NOT DETECT CONFIG FILE")
        return

    home = Home()
    home.set_auth_token(config.auth_token)
    home.init(config.access_point)

    if not home.get_current_state():
        return
    for ip in SCANABLE_DEVICES:
        try:
            res = ping3.ping(ip)
            if res != None:
                if DEACTIVATE_ON_PRESENCE:
                    for g in home.groups:
                        if isinstance(g, homematicip.group.SecurityZoneGroup
                                      ) and g.active:
                            print(
                                "someone is at home. Deactivating security zones"
                            )
                            home.set_security_zones_activation(False, False)
                            return
                    print(
                        "someone is at home and security zones are deactivated -> do nothing"
                    )
                else:
                    print("someone is at home -> do nothing")
                return
        except gaierror:
            print("could not resolve {}. Marking it as \"not at home\"".format(
                ip))

    print("Noone is home -> activating security zones")
    home.set_security_zones_activation(ACTIVATE_INTERNAL_ZONE,
                                       ACTIVATE_EXTERNAL_ZONE)
示例#10
0
class Exporter(object):
    """
    Prometheus Exporter for Homematic IP devices
    """
    def __init__(self, args):
        """
        initializes the exporter

        :param args: the argparse.Args
        """

        self.__home_client = None
        self.__metric_port = int(args.metric_port)
        self.__collect_interval_seconds = args.collect_interval_seconds
        self.__log_level = int(args.log_level)

        logging.info(
            "using config file '{}' and exposing metrics on port '{}'".format(
                args.config_file, self.__metric_port))

        self.__init_client(args.config_file, args.auth_token,
                           args.access_point, args.enable_event_metrics)
        self.__init_metrics()
        self.__collect_homematicip_info()
        try:
            prometheus_client.start_http_server(self.__metric_port)
        except Exception as e:
            logging.fatal(
                "starting the http server on port '{}' failed with: {}".format(
                    self.__metric_port, str(e)))
            sys.exit(1)

    def __init_client(self, config_file, auth_token, access_point,
                      enable_event_metrics):
        if auth_token and access_point:
            config = homematicip.HmipConfig(
                auth_token=auth_token,
                access_point=access_point,
                log_level=self.__log_level,
                log_file='hmip.log',
                raw_config=None,
            )
        else:
            config = homematicip.load_config_file(config_file=config_file)

        try:
            self.__home_client = Home()
            self.__home_client.set_auth_token(config.auth_token)
            self.__home_client.init(config.access_point)
            # metrics on events
            if enable_event_metrics:
                self.__home_client.onEvent += self.__collect_event_metrics
                self.__home_client.enable_events()
        except Exception as e:
            logging.fatal(
                "Initializing HomematicIP client failed with: {}".format(
                    str(e)))
            sys.exit(1)

    def __init_metrics(self):
        namespace = 'homematicip'
        labelnames = ['room', 'device_label']
        detail_labelnames = [
            'device_type', 'firmware_version', 'permanently_reachable'
        ]
        event_device_labelnames = ['device_label']
        event_group_labelnames = ['group_label']
        event_labelnames = ['type', 'window_state', 'sabotage']

        self.version_info = prometheus_client.Gauge(
            name='version_info',
            documentation='HomematicIP info',
            labelnames=['api_version'],
            namespace=namespace)
        self.metric_temperature_actual = prometheus_client.Gauge(
            name='temperature_actual',
            documentation='Actual temperature',
            labelnames=labelnames,
            namespace=namespace)
        self.metric_temperature_setpoint = prometheus_client.Gauge(
            name='temperature_setpoint',
            documentation='Set point temperature',
            labelnames=labelnames,
            namespace=namespace)
        self.metric_valve_adaption_needed = prometheus_client.Gauge(
            name='valve_adaption_needed',
            documentation='must the adaption re-run?',
            labelnames=labelnames,
            namespace=namespace)
        self.metric_temperature_offset = prometheus_client.Gauge(
            name='temperature_offset',
            documentation='the offset temperature for the thermostat',
            labelnames=labelnames,
            namespace=namespace)
        self.metric_valve_position = prometheus_client.Gauge(
            name='valve_position',
            documentation=
            'the current position of the valve 0.0 = closed, 1.0 max opened',
            labelnames=labelnames,
            namespace=namespace)
        self.metric_humidity_actual = prometheus_client.Gauge(
            name='humidity_actual',
            documentation='Actual Humidity',
            labelnames=labelnames,
            namespace=namespace)
        self.metric_last_status_update = prometheus_client.Gauge(
            name='last_status_update',
            documentation="Device last status update",
            labelnames=labelnames,
            namespace=namespace)
        self.metric_device_info = prometheus_client.Gauge(
            name='device_info',
            documentation='Device information',
            labelnames=labelnames + detail_labelnames,
            namespace=namespace)
        self.metric_power_consumption = prometheus_client.Gauge(
            name='power_consumption',
            documentation='Power consumption',
            labelnames=labelnames,
            namespace=namespace)
        self.metric_device_event = prometheus_client.Counter(
            name='device_event',
            documentation='events triggered by a device',
            labelnames=event_device_labelnames + event_labelnames,
            namespace=namespace)
        self.metric_group_event = prometheus_client.Counter(
            name='group_event',
            documentation='events triggered by a group',
            labelnames=event_group_labelnames + event_labelnames,
            namespace=namespace,
        )

    def __collect_homematicip_info(self):
        try:
            self.version_info.labels(
                api_version=self.__home_client.currentAPVersion).set(1)
            logging.debug("current homematic ip api version: '{}'".format(
                self.__home_client.currentAPVersion))
        except Exception as e:
            logging.warning("collecting version info failed with: {}".format(
                str(e)))

    def __collect_thermostat_metrics(self, room, device):
        if device.actualTemperature:
            self.metric_temperature_actual.labels(
                room=room,
                device_label=device.label).set(device.actualTemperature)

        if device.setPointTemperature:
            self.metric_temperature_setpoint.labels(
                room=room,
                device_label=device.label).set(device.setPointTemperature)

        if device.humidity:
            self.metric_humidity_actual.labels(room=room,
                                               device_label=device.label).set(
                                                   device.humidity)
        logging.info(
            "room: {}, label: {}, temperature_actual: {}, temperature_setpoint: {}, humidity_actual: {}"
            .format(room, device.label, device.actualTemperature,
                    device.setPointTemperature, device.humidity))

    def __collect_heating_metrics(self, room, device):

        # Do not check with if as 0 equals false
        self.metric_temperature_actual.labels(
            room=room,
            device_label=device.label).set(device.valveActualTemperature)
        self.metric_temperature_setpoint.labels(room=room,
                                                device_label=device.label).set(
                                                    device.setPointTemperature)
        self.metric_valve_adaption_needed.labels(
            room=room,
            device_label=device.label).set(device.automaticValveAdaptionNeeded)
        self.metric_temperature_offset.labels(room=room,
                                              device_label=device.label).set(
                                                  device.temperatureOffset)
        self.metric_valve_position.labels(
            room=room, device_label=device.label).set(device.valvePosition)

        logging.info(
            "room: {}, label: {}, temperature_actual: {}, temperature_setpoint: {}, valve_adaption_needed: {}, "
            "temperature_offset {}, valve_position: {}".format(
                room, device.label, device.valveActualTemperature,
                device.setPointTemperature,
                device.automaticValveAdaptionNeeded, device.temperatureOffset,
                device.valvePosition))

    def __collect_device_info_metrics(self, room, device):
        logging.info(
            "found device: room: {}, label: {}, device_type: {}, firmware_version: {}, last_status_update: {}, permanently_reachable: {}"
            .format(room, device.label, device.deviceType.lower(),
                    device.firmwareVersion, device.lastStatusUpdate,
                    device.permanentlyReachable))
        # general device info metric
        self.metric_device_info.labels(
            room=room,
            device_label=device.label,
            device_type=device.deviceType.lower(),
            firmware_version=device.firmwareVersion,
            permanently_reachable=device.permanentlyReachable).set(1)
        if device.lastStatusUpdate:
            # last status update metric
            self.metric_last_status_update.labels(
                room=room, device_label=device.label).set(
                    device.lastStatusUpdate.timestamp())

    def __collect_power_metrics(self, room, device):
        logging.info(
            "found device: room: {}, label: {}, device_type: {}, firmware_version: {}, last_status_update: {}, permanently_reachable: {}"
            .format(room, device.label, device.deviceType.lower(),
                    device.firmwareVersion, device.lastStatusUpdate,
                    device.permanentlyReachable))
        # general device info metric
        logging.info(device.currentPowerConsumption)
        self.metric_power_consumption.labels(
            room=room,
            device_label=device.label).set(device.currentPowerConsumption)

    def __collect_event_metrics(self, eventList):
        for event in eventList:
            type = event["eventType"]
            data = event["data"]

            if type is EventType.DEVICE_CHANGED:
                _window_state = _sabotage = None
                if isinstance(data, ShutterContact):
                    _window_state = str(data.windowState).lower()
                    _sabotage = str(data.sabotage).lower()
                    self.metric_device_event.labels(device_label=data.label,
                                                    type=str(type).lower(),
                                                    window_state=_window_state,
                                                    sabotage=_sabotage).inc()
                    logging.info(
                        "got device event type: {}, label: {}, window_state: {}, sabotage: {}"
                        .format(type, data.label, _window_state, _sabotage))

    def collect(self):
        """
        collect discovers all devices and generates metrics
        """
        try:
            self.__home_client.get_current_state()
            for g in self.__home_client.groups:
                if g.groupType == "META":
                    for d in g.devices:
                        # collect general device metrics
                        self.__collect_device_info_metrics(g.label, d)
                        # collect temperature, humidity
                        if isinstance(d,
                                      (WallMountedThermostatPro,
                                       TemperatureHumiditySensorDisplay,
                                       TemperatureHumiditySensorWithoutDisplay,
                                       TemperatureHumiditySensorOutdoor)):
                            self.__collect_thermostat_metrics(g.label, d)
                        elif isinstance(d, HeatingThermostat):
                            logging.info("Device of type heating")
                            self.__collect_heating_metrics(g.label, d)
                        elif isinstance(d, PlugableSwitchMeasuring):
                            logging.info(
                                "Device of type PlugableSwitchMeasuring")
                            self.__collect_power_metrics(g.label, d)

        except Exception as e:
            logging.warning(
                "collecting status from device(s) failed with: {1}".format(
                    str(e)))
        finally:
            logging.info('waiting {}s before next collection cycle'.format(
                self.__collect_interval_seconds))
            time.sleep(self.__collect_interval_seconds)
示例#11
0
def main():
    parser = ArgumentParser(
        description="a cli wrapper for the homematicip API")
    parser.add_argument(
        "--config_file",
        type=str,
        help=
        "the configuration file. If nothing is specified the script will search for it."
    )
    parser.add_argument(
        "--debug-level",
        dest="debug_level",
        type=int,
        help="the debug level which should get used(Critical=50, DEBUG=10)")

    group = parser.add_argument_group("Display Configuration")
    group.add_argument("--dump-configuration",
                       action="store_true",
                       dest="dump_config",
                       help="dumps the current configuration from the AP")
    group.add_argument("--list-devices",
                       action="store_true",
                       dest="list_devices",
                       help="list all devices")
    group.add_argument("--list-groups",
                       action="store_true",
                       dest="list_groups",
                       help="list all groups")
    group.add_argument("--list-group-ids",
                       action="store_true",
                       dest="list_group_ids",
                       help="list all groups and their ids")
    group.add_argument("--list-firmware",
                       action="store_true",
                       dest="list_firmware",
                       help="list the firmware of all devices")
    group.add_argument("--list-rssi",
                       action="store_true",
                       dest="list_rssi",
                       help="list the reception quality of all devices")
    group.add_argument("--list-events",
                       action="store_true",
                       dest="list_events",
                       help="prints all the events")
    group.add_argument("--list-last-status-update",
                       action="store_true",
                       dest="list_last_status_update",
                       help="prints the last status update of all systems")

    parser.add_argument("--list-security-journal",
                        action="store_true",
                        dest="list_security_journal",
                        help="display the security journal")
    parser.add_argument("--list-rules",
                        action="store_true",
                        dest="list_rules",
                        help="display all automation rules")

    parser.add_argument(
        "-d",
        "--device",
        dest="device",
        action='append',
        help=
        "the device you want to modify (see \"Device Settings\").\nYou can use * to modify all devices or enter the parameter multiple times to modify more devices"
    )
    parser.add_argument(
        "-g",
        "--group",
        dest="group",
        help="the group you want to modify (see \"Group Settings\")")

    group = parser.add_argument_group("Device Settings")
    group.add_argument("--turn-on",
                       action="store_true",
                       dest="device_switch_state",
                       help="turn the switch on",
                       default=None)
    group.add_argument("--set-dimmer",
                       action="store",
                       dest="set_dimmer",
                       help="turn the switch on",
                       default=None)
    group.add_argument("--turn-off",
                       action="store_false",
                       dest="device_switch_state",
                       help="turn the switch off",
                       default=None)
    group.add_argument("--set-shutter-level",
                       action="store",
                       dest="device_shutter_level",
                       help="set shutter to level (0..1)")
    group.add_argument("--set-shutter-stop",
                       action="store_true",
                       dest="device_shutter_stop",
                       help="stop shutter",
                       default=None)
    group.add_argument("--set-label",
                       dest="device_new_label",
                       help="set a new label")
    group.add_argument("--set-display",
                       dest="device_display",
                       action="store",
                       help="set the display mode",
                       choices=["actual", "setpoint", "actual_humidity"])
    group.add_argument("--enable-router-module",
                       action="store_true",
                       dest="device_enable_router_module",
                       help="enables the router module of the device",
                       default=None)
    group.add_argument("--disable-router-module",
                       action="store_false",
                       dest="device_enable_router_module",
                       help="disables the router module of the device",
                       default=None)

    group = parser.add_argument_group("Home Settings")
    group.add_argument("--set-protection-mode",
                       dest="protectionmode",
                       action="store",
                       help="set the protection mode",
                       choices=["presence", "absence", "disable"])
    group.add_argument("--set-pin",
                       dest="new_pin",
                       action="store",
                       help="set a new pin")
    group.add_argument("--delete-pin",
                       dest="delete_pin",
                       action="store_true",
                       help="deletes the pin")
    group.add_argument(
        "--old-pin",
        dest="old_pin",
        action="store",
        help="the current pin. used together with --set-pin or --delete-pin",
        default=None)
    group.add_argument("--set-zones-device-assignment",
                       dest="set_zones_device_assignment",
                       action="store_true",
                       help="sets the zones devices assignment")
    group.add_argument("--external-devices",
                       dest="external_devices",
                       nargs='+',
                       help="sets the devices for the external zone")
    group.add_argument("--internal-devices",
                       dest="internal_devices",
                       nargs='+',
                       help="sets the devices for the internal zone")
    group.add_argument("--activate-absence",
                       dest="activate_absence",
                       action="store",
                       help="activates absence for provided amount of minutes",
                       default=None,
                       type=int)
    group.add_argument("--deactivate-absence",
                       action="store_true",
                       dest="deactivate_absence",
                       help="deactivates absence")

    group = parser.add_argument_group("Group Settings")
    group.add_argument("--list-profiles",
                       dest="group_list_profiles",
                       action="store_true",
                       help="displays all profiles for a group")
    group.add_argument(
        "--activate-profile",
        dest="group_activate_profile",
        help="activates a profile by using its index or its name")
    group.add_argument("--set-group-shutter-level",
                       action="store",
                       dest="group_shutter_level",
                       help="set all shutters in group to level (0..1)")
    group.add_argument("--set-group-shutter-stop",
                       action="store_true",
                       dest="group_shutter_stop",
                       help="stop all shutters in group",
                       default=None)
    group.add_argument(
        "--set-point-temperature",
        action="store",
        dest="group_set_point_temperature",
        help=
        "sets the temperature for the given group. The group must be of the type \"HEATING\"",
        default=None,
        type=float)

    group.add_argument("--set-boost",
                       action="store_true",
                       dest="group_boost",
                       help="activates the boost mode for a HEATING group",
                       default=None)
    group.add_argument("--set-boost-stop",
                       action="store_false",
                       dest="group_boost",
                       help="deactivates the boost mode for a HEATING group",
                       default=None)

    if len(sys.argv) == 1:
        parser.print_help()
        return

    try:
        args = parser.parse_args()
    except:
        print('could not parse arguments')
        parser.print_help()
        return

    _config = None

    if args.config_file:
        try:
            _config = homematicip.load_config_file(args.config_file)
        except FileNotFoundError:
            print("##### CONFIG FILE NOT FOUND: {} #####".format(
                args.config_file))
            return
    else:
        convert_config2ini()
        _config = homematicip.find_and_load_config_file()

    if _config is None:
        print("Could not find configuration file. Script will exit")
        return

    global logger
    logger = create_logger(
        args.debug_level if args.debug_level else _config.log_level,
        _config.log_file)

    home = Home()
    home.set_auth_token(_config.auth_token)
    home.init(_config.access_point)

    if not home.get_current_state():
        return

    command_entered = False

    if args.dump_config:
        command_entered = True
        json_state = home.download_configuration()
        if "errorCode" in json_state:
            logger.error(
                "Could not get the current configuration. Error: {}".format(
                    json_state["errorCode"]))
        else:
            print(json.dumps(json_state, indent=4, sort_keys=True))

    if args.list_devices:
        command_entered = True
        sortedDevices = sorted(home.devices,
                               key=attrgetter('deviceType', 'label'))
        for d in sortedDevices:
            print(u'{} {}'.format(d.id, str(d)))

    if args.list_groups:
        command_entered = True
        sortedGroups = sorted(home.groups,
                              key=attrgetter('groupType', 'label'))
        for g in sortedGroups:
            print(str(g))

    if args.list_last_status_update:
        command_entered = True
        print(u'Devices:')
        sortedDevices = sorted(home.devices,
                               key=attrgetter('deviceType', 'label'))
        for d in sortedDevices:
            print(u'\t{}\t{}\t{}'.format(d.id, d.label, d.lastStatusUpdate))
        print(u'Groups:')
        sortedGroups = sorted(home.groups,
                              key=attrgetter('groupType', 'label'))
        for g in sortedGroups:
            print(u'\t{}\t{}\t{}'.format(g.groupType, g.label,
                                         g.lastStatusUpdate))

    if args.list_group_ids:
        command_entered = True
        sortedGroups = sorted(home.groups,
                              key=attrgetter('groupType', 'label'))
        for g in sortedGroups:
            print("Id: {} - Type: {} - Label: {}".format(
                g.id, g.groupType, g.label))

    if args.protectionmode:
        command_entered = True
        if args.protectionmode == "presence":
            home.set_security_zones_activation(False, True)
        elif args.protectionmode == "absence":
            home.set_security_zones_activation(True, True)
        elif args.protectionmode == "disable":
            home.set_security_zones_activation(False, False)

    if args.new_pin:
        command_entered = True
        home.set_pin(args.new_pin, args.old_pin)
    if args.delete_pin:
        command_entered = True
        home.set_pin(None, args.old_pin)

    if args.list_security_journal:
        command_entered = True
        journal = home.get_security_journal()
        for entry in journal:
            print(str(entry))

    if args.list_firmware:
        command_entered = True
        print(
            str("{:45s} - Firmware: {:6} - Available Firmware: {:6} UpdateState: {}"
                .format(
                    "HmIP AccessPoint", home.currentAPVersion
                    if home.currentAPVersion is not None else "None",
                    home.availableAPVersion if home.availableAPVersion
                    is not None else "None", home.updateState)))
        sortedDevices = sorted(home.devices,
                               key=attrgetter('deviceType', 'label'))
        for d in sortedDevices:
            print(
                str("{:45s} - Firmware: {:6} - Available Firmware: {:6} UpdateState: {}"
                    .format(
                        d.label, d.firmwareVersion, d.availableFirmwareVersion
                        if d.availableFirmwareVersion is not None else "None",
                        d.updateState)))

    if args.list_rssi:
        command_entered = True

        print(
            str("{:45s} - Duty cycle: {:2}".format(
                "HmIP AccessPoint",
                home.dutyCycle if home.dutyCycle is not None else "None")))

        sortedDevices = sorted(home.devices,
                               key=attrgetter('deviceType', 'label'))
        for d in sortedDevices:
            print(
                str("{:45s} - RSSI: {:4} {} - Peer RSSI: {:4} - {} {}".format(
                    d.label, d.rssiDeviceValue
                    if d.rssiDeviceValue is not None else "None",
                    getRssiBarString(d.rssiDeviceValue),
                    d.rssiPeerValue if d.rssiPeerValue is not None else "None",
                    getRssiBarString(d.rssiPeerValue),
                    "Unreachable" if d.unreach else "")))
    if args.list_rules:
        command_entered = True
        sortedRules = sorted(home.rules, key=attrgetter('ruleType', 'label'))
        for d in sortedRules:
            print(u'{} {}'.format(d.id, str(d)))

    if args.device:
        command_entered = False
        devices = []
        for argdevice in args.device:
            if argdevice == '*':
                devices = home.devices
                break
            else:
                d = home.search_device_by_id(argdevice)
                if d == None:
                    logger.error("Could not find device {}".format(argdevice))
                else:
                    devices.append(d)

        for device in devices:

            if args.device_new_label:
                device.set_label(args.device_new_label)
                command_entered = True
            if args.device_switch_state != None:
                if isinstance(device, PlugableSwitch):
                    device.set_switch_state(args.device_switch_state)
                    command_entered = True
                else:
                    logger.error(
                        "can't turn on/off device {} of type {}".format(
                            device.id, device.deviceType))

            if args.set_dimmer is not None:
                if isinstance(device, BrandDimmer):
                    device.set_dim_level(args.set_dimmer)
                    command_entered = True
                else:
                    logger.error("can't set device {} of type {}".format(
                        device.id, device.deviceType))

            if args.device_shutter_level is not None:
                if isinstance(device, FullFlushShutter):
                    device.set_shutter_level(args.device_shutter_level)
                    command_entered = True
                else:
                    logger.error(
                        "can't set shutter level of device {} of type {}".
                        format(device.id, device.deviceType))

            if args.device_shutter_stop is not None:
                if isinstance(device, FullFlushShutter):
                    device.set_shutter_stop()
                    command_entered = True
                else:
                    logger.error(
                        "can't stop shutter of device {} of type {}".format(
                            device.id, device.deviceType))

            if args.device_display != None:
                if isinstance(device, TemperatureHumiditySensorDisplay):
                    device.set_display(args.device_display.upper())
                    command_entered = True
                else:
                    logger.error(
                        "can't set display of device {} of type {}".format(
                            device.id, device.deviceType))

            if args.device_enable_router_module != None:
                if device.routerModuleSupported:
                    device.set_router_module_enabled(
                        args.device_enable_router_module)
                    print("{} the router module for device {}".format(
                        "Enabled" if args.device_enable_router_module else
                        "Disabled", device.id))
                    command_entered = True
                else:
                    logger.error(
                        "the device {} doesn't support the router module".
                        format(device.id))

    if args.set_zones_device_assignment:
        internal = []
        external = []
        error = False
        command_entered = True
        for id in args.external_devices:
            d = home.search_device_by_id(id)
            if d == None:
                logger.error(
                    "Device {} is not registered on this Access Point".format(
                        id))
                error = True
            else:
                external.append(d)

        for id in args.internal_devices:
            d = home.search_device_by_id(id)
            if d == None:
                logger.error(
                    "Device {} is not registered on this Access Point".format(
                        id))
                error = True
            else:
                internal.append(d)
        if not error:
            home.set_zones_device_assignment(internal, external)

    if args.activate_absence:
        command_entered = True
        home.activate_absence_with_duration(args.activate_absence)

    if args.deactivate_absence:
        command_entered = True
        home.deactivate_absence()

    if args.group:
        command_entered = False
        group = None
        for g in home.groups:
            if g.id == args.group:
                group = g
                break
        if group == None:
            logger.error("Could not find group {}".format(args.group))
            return

        if args.group_list_profiles:
            command_entered = True
            for p in group.profiles:
                isActive = p.id == group.activeProfile.id
                print("Index: {} - Id: {} - Name: {} - Active: {}".format(
                    p.index, p.id, p.name, isActive))

        if args.group_shutter_level:
            command_entered = True
            group.set_shutter_level(args.group_shutter_level)

        if args.group_shutter_stop:
            command_entered = True
            group.set_shutter_stop()

        if args.group_set_point_temperature:
            command_entered = True
            if isinstance(group, HeatingGroup):
                group.set_point_temperature(args.group_set_point_temperature)
            else:
                logger.error("Group {} isn't a HEATING group".format(g.id))

        if args.group_activate_profile:
            command_entered = True
            if isinstance(group, HeatingGroup):
                index = args.group_activate_profile
                for p in group.profiles:
                    if p.name == args.group_activate_profile:
                        index = p.index
                        break
                group.set_active_profile(index)
            else:
                logger.error("Group {} isn't a HEATING group".format(g.id))

        if args.group_boost is not None:
            command_entered = True
            if isinstance(group, HeatingGroup):
                group.set_boost(args.group_boost)
            else:
                logger.error("Group {} isn't a HEATING group".format(g.id))

    if args.list_events:
        command_entered = True
        home.onEvent += printEvents
        home.enable_events()
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            return

    if not command_entered:
        parser.print_help()
示例#12
0
def main():

    _config = homematicip.find_and_load_config_file()
    if _config is None:
        print("Could not find configuration file. Script will exit")
        return

    global logger
    logger = create_logger(_config.log_level, _config.log_file)

    home = Home()
    home.set_auth_token(_config.auth_token)
    home.init(_config.access_point)

    locale.setlocale(locale.LC_ALL, '')

    if not home.get_current_state():
        print("home.get_current_state()={}".format(home.get_current_state()))
        return

    sortedGroups = sorted(home.groups, key=attrgetter("groupType", "label"))
    for g in sortedGroups:
        # print(type(g).__name__ +" "+g.label+":")
        if (isinstance(g, HeatingGroup)):
            # first print Sensor
            print("HeatingGroup " + g.label + ":")
            sensorDevices = []
            heatingThermostats = []
            plugableSwitchMeasurings = []
            for d in g.devices:
                if isinstance(d, TemperatureHumiditySensorWithoutDisplay):
                    # https://homematicip-rest-api.readthedocs.io/en/latest/homematicip.html#homematicip.device.TemperatureHumiditySensorWithoutDisplay
                    sensorDevices.append(d)
                elif isinstance(d, HeatingThermostat):
                    heatingThermostats.append(d)
                elif isinstance(d, PlugableSwitchMeasuring):
                    plugableSwitchMeasurings.append(d)

            if (len(heatingThermostats) > 0
                    or len(plugableSwitchMeasurings) > 0):
                fileName = g.label + ".csv"
                if os.path.isfile(fileName):
                    f = open(fileName, "a+")
                else:
                    f = open(fileName, "a+")
                    f.write("date\tactual\thumidity")
                    for d in heatingThermostats:
                        f.write("\tset\tvalve")
                    for d in plugableSwitchMeasurings:
                        f.write("\tsum\tcurrent")
                    f.write("\n")
                for d in sorted(sensorDevices):
                    print("  humidity {} {} {}".format(
                        d.label, locale.str(d.actualTemperature),
                        locale.str(d.humidity)))
                    f.write("{}\t{}\t{}".format(
                        datetime.now(), locale.str(d.actualTemperature),
                        locale.str(d.humidity)))
                # Then all HeatingThermostat
                for d in sorted(heatingThermostats):
                    print("  valvePosition {} {} {}".format(
                        d.label, locale.str(d.setPointTemperature),
                        locale.str(d.valvePosition * 100)))
                    f.write("\t{}\t{}".format(
                        locale.str(d.setPointTemperature),
                        locale.str(d.valvePosition * 100)))
                # Then all PlugableSwitchMeasuring
                for d in sorted(plugableSwitchMeasurings):
                    if (d.energyCounter is None
                            or d.currentPowerConsumption is None):
                        print(d)
                    else:
                        print("  energy {} {} {}".format(
                            d.label, locale.str(d.energyCounter),
                            locale.str(d.currentPowerConsumption)))
                        f.write("\t{}\t{}".format(
                            locale.str(d.energyCounter),
                            locale.str(d.currentPowerConsumption)))
                f.write("\n")
                f.close()

    # print all valve positions in one file
    sortedDevices = sorted(home.devices, key=attrgetter("deviceType", "label"))
    fileName = "valvePositions.csv"
    if os.path.isfile(fileName):
        f = open(fileName, "a+")
    else:
        f = open(fileName, "a+")
        f.write("date")
        for d in sortedDevices:
            if isinstance(d, HeatingThermostat):
                f.write("\t{}".format(d.label))
        f.write("\n")
    f.write("{}".format(datetime.now()))
    for d in sortedDevices:
        if isinstance(d, HeatingThermostat):
            f.write("\t{}".format(locale.str(d.valvePosition * 100)))
    f.write("\n")
    f.close()

    # print all temperatures in one file
    sortedDevices = sorted(home.devices, key=attrgetter("deviceType", "label"))
    fileName = "temperatures.csv"
    if os.path.isfile(fileName):
        f = open(fileName, "a+")
    else:
        f = open(fileName, "a+")
        f.write("date")
        for d in sortedDevices:
            if isinstance(d, TemperatureHumiditySensorWithoutDisplay):
                f.write("\t{}\t".format(d.label))
        f.write("\n")
    f.write("{}".format(datetime.now()))
    for d in sortedDevices:
        if isinstance(d, TemperatureHumiditySensorWithoutDisplay):
            f.write("\t{}\t{}".format(locale.str(d.actualTemperature),
                                      locale.str(d.humidity)))
    f.write("\n")
    f.close()
示例#13
0
class HmipClient:
    def __init__(self):
        LOGGER.info("HmipClient initializing...")
        self.readConfig()
        self.setup()
        LOGGER.info("HmipClient initialized.")

    def readConfig(self):
        config = configparser.ConfigParser()
        config.read('config.ini')
        self.hmip_authtoken = config['HMIP_AUTH']['authtoken']
        self.hmip_accesspoint = config['HMIP_AUTH']['accesspoint']

    def on_update_handler(self, data, event_type, obj):
        if obj:
            data['api_name'] = obj.__class__.__name__
        now = time.time()
        data['timestamp'] = now
        LOGGER.debug(datetime.fromtimestamp(now).strftime('%Y-%m-%d_%H-%M-%S'))
        LOGGER.debug(pprint.pformat(data))
        label = data['label'].replace(" ", "_")
        obj_type = ''
        if obj:
            obj_type = obj.__class__.__name__
#        sid = data['id'];
        self.publishHandler.handle(event_type, obj_type, label, data)
        # save the data.
        #_file_name = '{}_{}.json'.format(obj.__class__.__name__,
        #                                 datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S'))
        #_full_path = os.path.join('tests/json_data', _file_name)
        #with open(_full_path, 'w') as fl:
        #    json.dump(data, fl, indent=4)

    async def get_async_home(self):
        LOGGER.info("get_async_home")
        self.async_home = AsyncHome(self.loop)
        LOGGER.debug("AuthToken=" + self.hmip_authtoken)
        LOGGER.debug("AccessPoint=" + self.hmip_accesspoint)
        self.async_home.set_auth_token(self.hmip_authtoken)
        await self.async_home.init(self.hmip_accesspoint)
        return self.async_home

    def get_home(self):
        self.home = Home()
        self.home.set_auth_token(self.hmip_authtoken)
        self.home.init(self.hmip_accesspoint)

    async def update_state(self):
        LOGGER.info("update_state " + str(self.async_home))
        await self.async_home.get_current_state()
        LOGGER.info("update_start success")
        for d in self.async_home.devices:
            LOGGER.debug('{} {} {}'.format(d.id, d.label, str(d)))
        for g in self.async_home.groups:
            LOGGER.debug('{} {} {}'.format(g.id, g.label, str(g)))

    async def wait_for_ws_incoming(self):
        await self.async_home.get_current_state()
        for d in self.async_home.devices:
            d.on_update(self.on_update_handler)
        for d in self.async_home.groups:
            d.on_update(self.on_update_handler)
        reader = await self.async_home.enable_events()
        await reader

    def readConfiguration(self):
        self.home.get_current_state()
        LOGGER.debug("Devices:")
        for d in self.home.devices:
            LOGGER.debug('  {} {} {}'.format(d.id, d.label, str(d)))
        LOGGER.debug("Groups:")
        for g in self.home.groups:
            LOGGER.debug('  {} {} {}'.format(g.id, g.label, str(g)))
        LOGGER.debug("Profiles:")
        for g in self.home.groups:
            if hasattr(g, 'profiles'):
                LOGGER.debug("  Profiles for Group {}".format(g.label))
                for p in g.profiles:
                    p.get_details()
                    LOGGER.debug(
                        "    name={} id={} groupId={} homeId={}".format(
                            p.name, p.id, p.groupId, p.homeId))
                    for day in p.profileDays:
                        for period in p.profileDays[day].periods:
                            if isinstance(period, HeatingCoolingPeriod):
                                LOGGER.debug(
                                    "    HeatingCoolingPeriod: Day={} start={} end={} value={}"
                                    .format(day, period.starttime,
                                            period.endtime, period.value))
                            elif isinstance(period, TimeProfilePeriod):
                                LOGGER.debug(
                                    "    TimeProfilePeriod: Day={} hour={} minute={} dimLevel={}"
                                    .format(day, period.hour, period.minute,
                                            period.dimLevel))
#                                     self.weekdays = []
#        self.hour = 0
#        self.minute = 0
#       self.astroOffset = 0
#       self.astroLimitationType = "NO_LIMITATION"  # NOT_EARLIER_THAN_TIME, NOT_LATER_THAN_TIME
#       self.switchTimeMode = "REGULAR_SWITCH_TIME"  # ASTRO_SUNRISE_SWITCH_TIME, ASTRO_SUNSET_SWITCH_TIME
#       self.dimLevel = 1.0
#       self.rampTime = 0
                            else:
                                LOGGER.debug(
                                    "    Unknown: Day={} period={}".format(
                                        day, period))
#        self.jsonConf = self.async_home.download_configuration()
#        LOGGER.debug("Configuration: \n{}".format(self.jsonConf))

    def setup(self):
        self.loop = asyncio.get_event_loop()

        self.get_home()
        self.readConfiguration()

        self.async_home = None
        try:
            self.async_home = self.loop.run_until_complete(
                self.get_async_home())
#            self.loop.run_until_complete(self.readConfiguration())
        except HmipConnectionError:
            LOGGER.error("Problem connecting [get home]")
        if self.async_home:
            try:
                self.loop.run_until_complete(self.update_state())
            except HmipConnectionError:
                LOGGER.error("Problem connecting [update state]")

#        loop.close()
#        self.doLoop(None)

    def doLoop(self, mqttClient):
        self.mqtt_client = mqttClient
        self.publishHandler = HmipPublishHandler(mqttClient)
        LOGGER.info("HomematicIp Loop Start")
        try:
            self.loop.run_until_complete(self.wait_for_ws_incoming())
        except HmipConnectionError:
            LOGGER.error("Problem connecting [incoming]")
        except KeyboardInterrupt:
            self.loop.run_until_complete(
                self.async_home.close_websocket_connection())
        print("HomematicIp Loop End")
# coding=utf-8
import os.path

import config
import homematicip
from homematicip.home import Home

home = Home()
home.init(config.ACCESS_POINT)
home.set_auth_token(config.AUTH_TOKEN)

home.get_current_state()


def write_shutter(device):
    if not os.path.isfile("shutter.csv"):
        with open("shutter.csv", "w", encoding='utf-8') as csv:
            csv.write("name;timestamp;open/close\n")
    with open("shutter.csv", "a", encoding='utf-8') as csv:
        csv.write("{};{};{}\n".format(device.id, str(device.lastStatusUpdate),
                                      d.windowState))


def write_heatingthermostat(device):
    if not os.path.isfile("heatingthermostat.csv"):
        with open("heatingthermostat.csv", "w", encoding='utf-8') as csv:
            csv.write("name;timestamp;valveposition\n")
    with open("heatingthermostat.csv", "a", encoding='utf-8') as csv:
        csv.write("{};{};{}\n".format(device.id, str(device.lastStatusUpdate),
                                      d.valvePosition))
示例#15
0
import json

import homematicip
from flask import Flask
from homematicip.home import Home

config = homematicip.find_and_load_config_file()

home = Home()
home.set_auth_token(config.auth_token)
home.init(config.access_point)

app = Flask(__name__)


def get_heating_thermostat_as_json(device):
    return device._rawJSONData


@app.route('/homematic/devices')
def homematic_devices():
    home.get_current_state()
    response = []
    for group in home.groups:
        room = {"room": group.label, "devices": []}
        if group.groupType == "META":
            for device in group.devices:
                room["devices"].append(get_heating_thermostat_as_json(device))

            response.append(room)
    response = app.response_class(response=json.dumps(response),
def main():
    pd.set_option('display.width', 200)

    parser = ArgumentParser(
        description="a cli wrapper for the homematicip API")
    parser.add_argument(
        "--config_file",
        type=str,
        help=
        "the configuration file. If nothing is specified the script will search for it.",
    )

    parser.add_argument(
        "--interval",
        type=int,
        help=
        "the interval between two subsequent server requests for temperature data.",
    )

    try:
        args = parser.parse_args()
    except SystemExit:
        return
    except:
        print("could not parse arguments")
        parser.print_help()
        return

    _config = None
    if args.config_file:
        try:
            _config = homematicip.load_config_file(args.config_file)
        except FileNotFoundError:
            print("##### CONFIG FILE NOT FOUND: {} #####".format(
                args.config_file))
            return
    else:
        _config = homematicip.find_and_load_config_file()
    if _config is None:
        print("Could not find configuration file. Script will exit")
        return

    _interval = 10
    if args.interval:
        _interval = args.interval
        print("Using the interval: " + str(_interval))
    else:
        print("Using the default interval: " + str(_interval))

    home = Home()
    home.set_auth_token(_config.auth_token)
    home.init(_config.access_point)

    if not home.get_current_state():
        print("homematicip cannot get its current state.")
        return
    print("\n=== Homematicip Initialized ===\n")

    rooms_history = {}

    data = []
    i = 0

    # Check if the log file already exist
    if os.path.isfile(log_file):
        df = pd.read_csv(log_file)
        data = df.values.tolist()
        print(str(len(data)) + " rows have been loaded from " + log_file)
        print("")

    while True:
        sortedGroups = [
            str(g)
            for g in sorted(home.groups, key=attrgetter("groupType", "label"))
        ]

        # Regex to extract (room name, target temperature, current temperature)
        regex = re.compile(
            r'HEATING (.*) window.*setPointTemperature\((\d+\.+\d*)\).*actualTemperature\((\d+\.+\d*)\)'
        )
        rooms = list(filter(regex.search, sortedGroups))

        # Add new measurement into the dictionary
        t = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        for r in rooms:
            data.append([
                t,
                regex.search(r).group(1),
                regex.search(r).group(2),
                regex.search(r).group(3)
            ])

        # Pandas Dataframe
        data_frame = pd.DataFrame(data,
                                  columns=[
                                      "time", "room", "target_temperature",
                                      "current_temperature"
                                  ])
        data_frame.to_csv(log_file, index=False)
        print("Temperature measurement index: " + str(i))
        i = i + 1
        # Read temperature data every _interval seconds
        time.sleep(_interval)
示例#17
0
def main():
    parser = ArgumentParser(
        description="a cli wrapper for the homematicip API")
    parser.add_argument(
        "--config_file",
        type=str,
        help=
        "the configuration file. If nothing is specified the script will search for it.",
    )
    parser.add_argument(
        "--server-config",
        type=str,
        dest="server_config",
        help=
        "the server configuration file. e.g. output from --dump-configuration.",
    )
    parser.add_argument(
        "--debug-level",
        dest="debug_level",
        type=int,
        help="the debug level which should get used(Critical=50, DEBUG=10)",
    )
    parser.add_argument(
        "--version",
        action="version",
        version="%(prog)s {}".format(homematicip.__version__),
    )

    group = parser.add_argument_group("Display Configuration")
    group.add_argument(
        "--dump-configuration",
        action="store_true",
        dest="dump_config",
        help="dumps the current configuration from the AP",
    )
    group.add_argument(
        "--anonymize",
        action="store_true",
        dest="anonymize",
        help="used together with --dump-configuration to anonymize the output",
    )
    group.add_argument(
        "--list-devices",
        action="store_true",
        dest="list_devices",
        help="list all devices",
    )
    group.add_argument("--list-groups",
                       action="store_true",
                       dest="list_groups",
                       help="list all groups")
    group.add_argument(
        "--list-group-ids",
        action="store_true",
        dest="list_group_ids",
        help="list all groups and their ids",
    )
    group.add_argument(
        "--list-firmware",
        action="store_true",
        dest="list_firmware",
        help="list the firmware of all devices",
    )
    group.add_argument(
        "--list-rssi",
        action="store_true",
        dest="list_rssi",
        help="list the reception quality of all devices",
    )
    group.add_argument(
        "--list-events",
        action="store_true",
        dest="list_events",
        help="prints all the events",
    )
    group.add_argument(
        "--list-last-status-update",
        action="store_true",
        dest="list_last_status_update",
        help="prints the last status update of all systems",
    )

    parser.add_argument(
        "--list-security-journal",
        action="store_true",
        dest="list_security_journal",
        help="display the security journal",
    )
    parser.add_argument(
        "--list-rules",
        action="store_true",
        dest="list_rules",
        help="display all automation rules",
    )

    parser.add_argument(
        "-d",
        "--device",
        dest="device",
        action="append",
        help=
        'the device you want to modify (see "Device Settings").\nYou can use * to modify all devices or enter the parameter multiple times to modify more devices',
    )
    parser.add_argument(
        "-g",
        "--group",
        dest="group",
        help='the group you want to modify (see "Group Settings")',
    )
    parser.add_argument(
        "-r",
        "--rule",
        dest="rules",
        action="append",
        help=
        'the automation you want to modify (see "Automation Rule Settings").\nYou can use * to modify all automations or enter the parameter multiple times to modify more automations',
    )

    group = parser.add_argument_group("Device Settings")
    group.add_argument(
        "--turn-on",
        action="store_true",
        dest="device_switch_state",
        help="turn the switch on",
        default=None,
    )
    group.add_argument(
        "--turn-off",
        action="store_false",
        dest="device_switch_state",
        help="turn the switch off",
        default=None,
    )
    group.add_argument(
        "--set-dim-level",
        action="store",
        dest="device_dim_level",
        help="set dimmer to level (0..1)",
        default=None,
    )
    group.add_argument(
        "--set-shutter-level",
        action="store",
        dest="device_shutter_level",
        help="set shutter to level (0..1)",
    )
    group.add_argument(
        "--set-shutter-stop",
        action="store_true",
        dest="device_shutter_stop",
        help="stop shutter",
        default=None,
    )
    group.add_argument("--set-label",
                       dest="device_new_label",
                       help="set a new label")
    group.add_argument(
        "--set-display",
        dest="device_display",
        action="store",
        help="set the display mode",
        choices=["actual", "setpoint", "actual_humidity"],
    )
    group.add_argument(
        "--enable-router-module",
        action="store_true",
        dest="device_enable_router_module",
        help="enables the router module of the device",
        default=None,
    )
    group.add_argument(
        "--disable-router-module",
        action="store_false",
        dest="device_enable_router_module",
        help="disables the router module of the device",
        default=None,
    )
    group.add_argument(
        "--reset-energy-counter",
        action="store_true",
        dest="reset_energy_counter",
        help="resets the energy counter",
    )

    group = parser.add_argument_group("Home Settings")
    group.add_argument(
        "--set-protection-mode",
        dest="protectionmode",
        action="store",
        help="set the protection mode",
        choices=["presence", "absence", "disable"],
    )
    group.add_argument("--set-pin",
                       dest="new_pin",
                       action="store",
                       help="set a new pin")
    group.add_argument("--delete-pin",
                       dest="delete_pin",
                       action="store_true",
                       help="deletes the pin")
    group.add_argument(
        "--old-pin",
        dest="old_pin",
        action="store",
        help="the current pin. used together with --set-pin or --delete-pin",
        default=None,
    )
    group.add_argument(
        "--set-zones-device-assignment",
        dest="set_zones_device_assignment",
        action="store_true",
        help="sets the zones devices assignment",
    )
    group.add_argument(
        "--external-devices",
        dest="external_devices",
        nargs="+",
        help="sets the devices for the external zone",
    )
    group.add_argument(
        "--internal-devices",
        dest="internal_devices",
        nargs="+",
        help="sets the devices for the internal zone",
    )
    group.add_argument(
        "--activate-absence",
        dest="activate_absence",
        action="store",
        help="activates absence for provided amount of minutes",
        default=None,
        type=int,
    )
    group.add_argument(
        "--deactivate-absence",
        action="store_true",
        dest="deactivate_absence",
        help="deactivates absence",
    )
    group.add_argument(
        "--start-inclusion",
        action="store",
        dest="inclusion_device_id",
        help="start inclusion for device with given id",
    )

    group = parser.add_argument_group("Group Settings")
    group.add_argument(
        "--list-profiles",
        dest="group_list_profiles",
        action="store_true",
        help="displays all profiles for a group",
    )
    group.add_argument(
        "--activate-profile",
        dest="group_activate_profile",
        help="activates a profile by using its index or its name",
    )
    group.add_argument(
        "--set-group-shutter-level",
        action="store",
        dest="group_shutter_level",
        help="set all shutters in group to level (0..1)",
    )
    group.add_argument(
        "--set-group-shutter-stop",
        action="store_true",
        dest="group_shutter_stop",
        help="stop all shutters in group",
        default=None,
    )
    group.add_argument(
        "--set-point-temperature",
        action="store",
        dest="group_set_point_temperature",
        help=
        'sets the temperature for the given group. The group must be of the type "HEATING"',
        default=None,
        type=float,
    )

    group.add_argument(
        "--set-boost",
        action="store_true",
        dest="group_boost",
        help="activates the boost mode for a HEATING group",
        default=None,
    )
    group.add_argument(
        "--set-boost-stop",
        action="store_false",
        dest="group_boost",
        help="deactivates the boost mode for a HEATING group",
        default=None,
    )
    group.add_argument(
        "--set-boost-duration",
        dest="group_boost_duration",
        action="store",
        help="sets the boost duration for a HEATING group in minutes",
        default=None,
        type=int,
    )

    group = parser.add_argument_group("Automation Rule Settings")
    group.add_argument(
        "--enable-rule",
        action="store_true",
        dest="rule_activation",
        help="activates the automation rules",
        default=None,
    )
    group.add_argument(
        "--disable-rule",
        action="store_false",
        dest="rule_activation",
        help="deactivates the automation rules",
        default=None,
    )

    if len(sys.argv) == 1:
        parser.print_help()
        return

    try:
        args = parser.parse_args()
    except SystemExit:
        return
    except:
        print("could not parse arguments")
        parser.print_help()
        return

    _config = None

    if args.config_file:
        try:
            _config = homematicip.load_config_file(args.config_file)
        except FileNotFoundError:
            print("##### CONFIG FILE NOT FOUND: {} #####".format(
                args.config_file))
            return
    else:
        _config = homematicip.find_and_load_config_file()

    if _config is None:
        print("Could not find configuration file. Script will exit")
        return

    global logger
    logger = create_logger(
        args.debug_level if args.debug_level else _config.log_level,
        _config.log_file)

    home = Home()
    home.set_auth_token(_config.auth_token)
    home.init(_config.access_point)

    command_entered = False
    if args.server_config:
        global server_config
        server_config = args.server_config
        home.download_configuration = fake_download_configuration

    if args.dump_config:
        command_entered = True
        json_state = home.download_configuration()

        output = handle_config(json_state, args.anonymize)
        if output:
            print(output)

    if not home.get_current_state():
        return

    if args.list_devices:
        command_entered = True
        sortedDevices = sorted(home.devices,
                               key=attrgetter("deviceType", "label"))
        for d in sortedDevices:
            print("{} {}".format(d.id, str(d)))

    if args.list_groups:
        command_entered = True
        sortedGroups = sorted(home.groups,
                              key=attrgetter("groupType", "label"))
        for g in sortedGroups:
            print(g)

    if args.list_last_status_update:
        command_entered = True
        print("Devices:")
        sortedDevices = sorted(home.devices,
                               key=attrgetter("deviceType", "label"))
        for d in sortedDevices:
            print("\t{}\t{}\t{}".format(d.id, d.label, d.lastStatusUpdate))
        print("Groups:")
        sortedGroups = sorted(home.groups,
                              key=attrgetter("groupType", "label"))
        for g in sortedGroups:
            print("\t{}\t{}\t{}".format(g.groupType, g.label,
                                        g.lastStatusUpdate))

    if args.list_group_ids:
        command_entered = True
        sortedGroups = sorted(home.groups,
                              key=attrgetter("groupType", "label"))
        for g in sortedGroups:
            print("Id: {} - Type: {} - Label: {}".format(
                g.id, g.groupType, g.label))

    if args.protectionmode:
        command_entered = True
        if args.protectionmode == "presence":
            home.set_security_zones_activation(False, True)
        elif args.protectionmode == "absence":
            home.set_security_zones_activation(True, True)
        elif args.protectionmode == "disable":
            home.set_security_zones_activation(False, False)

    if args.new_pin:
        command_entered = True
        home.set_pin(args.new_pin, args.old_pin)
    if args.delete_pin:
        command_entered = True
        home.set_pin(None, args.old_pin)

    if args.list_security_journal:
        command_entered = True
        journal = home.get_security_journal()
        for entry in journal:
            print(entry)

    if args.list_firmware:
        command_entered = True
        print(
            "{:45s} - Firmware: {:6} - Available Firmware: {:6} UpdateState: {}"
            .format(
                "HmIP AccessPoint",
                home.currentAPVersion
                if home.currentAPVersion is not None else "None",
                home.availableAPVersion
                if home.availableAPVersion is not None else "None",
                home.updateState,
            ))
        sortedDevices = sorted(home.devices,
                               key=attrgetter("deviceType", "label"))
        for d in sortedDevices:
            print(
                "{:45s} - Firmware: {:6} - Available Firmware: {:6} UpdateState: {} LiveUpdateState: {}"
                .format(
                    d.label,
                    d.firmwareVersion,
                    d.availableFirmwareVersion
                    if d.availableFirmwareVersion is not None else "None",
                    d.updateState,
                    d.liveUpdateState,
                ))

    if args.list_rssi:
        command_entered = True

        print("{:45s} - Duty cycle: {:2}".format(
            "HmIP AccessPoint",
            home.dutyCycle if home.dutyCycle is not None else "None",
        ))

        sortedDevices = sorted(home.devices,
                               key=attrgetter("deviceType", "label"))
        for d in sortedDevices:
            print(
                "{:45s} - RSSI: {:4} {} - Peer RSSI: {:4} - {} {} permanentlyReachable: {}"
                .format(
                    d.label,
                    d.rssiDeviceValue
                    if d.rssiDeviceValue is not None else "None",
                    getRssiBarString(d.rssiDeviceValue),
                    d.rssiPeerValue if d.rssiPeerValue is not None else "None",
                    getRssiBarString(d.rssiPeerValue),
                    "Unreachable" if d.unreach else "",
                    d.permanentlyReachable,
                ))
    if args.list_rules:
        command_entered = True
        sortedRules = sorted(home.rules, key=attrgetter("ruleType", "label"))
        for d in sortedRules:
            print("{} {}".format(d.id, str(d)))

    if args.device:
        command_entered = False
        devices = []
        for argdevice in args.device:
            if argdevice == "*":
                devices = home.devices
                break
            else:
                d = home.search_device_by_id(argdevice)
                if d == None:
                    logger.error("Could not find device %s", argdevice)
                else:
                    devices.append(d)

        for device in devices:

            if args.device_new_label:
                device.set_label(args.device_new_label)
                command_entered = True

            if args.device_switch_state is not None:
                if isinstance(device, Switch):
                    device.set_switch_state(args.device_switch_state)
                else:
                    logger.error(
                        "can't turn on/off device %s of type %s",
                        device.id,
                        device.deviceType,
                    )
                command_entered = True

            if args.device_dim_level is not None:
                if isinstance(device, Dimmer):
                    device.set_dim_level(args.device_dim_level)
                else:
                    logger.error(
                        "can't set dim level of device %s of type %s",
                        device.id,
                        device.deviceType,
                    )
                command_entered = True

            if args.device_shutter_level is not None:
                if isinstance(device, FullFlushShutter):
                    device.set_shutter_level(args.device_shutter_level)
                else:
                    logger.error(
                        "can't set shutter level of device %s of type %s",
                        device.id,
                        device.deviceType,
                    )
                command_entered = True

            if args.device_shutter_stop is not None:
                if isinstance(device, FullFlushShutter):
                    device.set_shutter_stop()
                else:
                    logger.error(
                        "can't stop shutter of device %s of type %s",
                        device.id,
                        device.deviceType,
                    )
                command_entered = True

            if args.device_display is not None:
                if isinstance(device, TemperatureHumiditySensorDisplay):
                    device.set_display(
                        ClimateControlDisplay(args.device_display.upper()))
                else:
                    logger.error(
                        "can't set display of device %s of type %s",
                        device.id,
                        device.deviceType,
                    )
                command_entered = True

            if args.device_enable_router_module is not None:
                if device.routerModuleSupported:
                    device.set_router_module_enabled(
                        args.device_enable_router_module)
                    print("{} the router module for device {}".format(
                        "Enabled"
                        if args.device_enable_router_module else "Disabled",
                        device.id,
                    ))
                else:
                    logger.error(
                        "the device %s doesn't support the router module",
                        device.id)
                command_entered = True

            if args.reset_energy_counter:
                if isinstance(device, SwitchMeasuring):
                    device.reset_energy_counter()
                    print("reset energycounter {}".format(device.id))
                else:
                    logger.error(
                        "can't reset energy counter for device %s of type %s",
                        device.id,
                        device.deviceType,
                    )
                command_entered = True

    if args.set_zones_device_assignment:
        internal = []
        external = []
        error = False
        command_entered = True
        for id in args.external_devices:
            d = home.search_device_by_id(id)
            if d == None:
                logger.error(
                    "Device %s is not registered on this Access Point", id)
                error = True
            else:
                external.append(d)

        for id in args.internal_devices:
            d = home.search_device_by_id(id)
            if d == None:
                logger.error(
                    "Device %s is not registered on this Access Point", id)
                error = True
            else:
                internal.append(d)
        if not error:
            home.set_zones_device_assignment(internal, external)

    if args.activate_absence:
        command_entered = True
        home.activate_absence_with_duration(args.activate_absence)

    if args.deactivate_absence:
        command_entered = True
        home.deactivate_absence()

    if args.inclusion_device_id:
        command_entered = True
        home.start_inclusion(args.inclusion_device_id)

    if args.group:
        command_entered = False
        group = None
        for g in home.groups:
            if g.id == args.group:
                group = g
                break
        if group == None:
            logger.error("Could not find group %s", args.group)
            return

        if args.group_list_profiles:
            command_entered = True
            for p in group.profiles:
                isActive = p.id == group.activeProfile.id
                print("Index: {} - Id: {} - Name: {} - Active: {}".format(
                    p.index, p.id, p.name, isActive))

        if args.group_shutter_level:
            command_entered = True
            group.set_shutter_level(args.group_shutter_level)

        if args.group_shutter_stop:
            command_entered = True
            group.set_shutter_stop()

        if args.group_set_point_temperature:
            command_entered = True
            if isinstance(group, HeatingGroup):
                group.set_point_temperature(args.group_set_point_temperature)
            else:
                logger.error("Group %s isn't a HEATING group", g.id)

        if args.group_activate_profile:
            command_entered = True
            if isinstance(group, HeatingGroup):
                index = args.group_activate_profile
                for p in group.profiles:
                    if p.name == args.group_activate_profile:
                        index = p.index
                        break
                group.set_active_profile(index)
            else:
                logger.error("Group %s isn't a HEATING group", g.id)

        if args.group_boost is not None:
            command_entered = True
            if isinstance(group, HeatingGroup):
                group.set_boost(args.group_boost)
            else:
                logger.error("Group %s isn't a HEATING group", g.id)

        if args.group_boost_duration is not None:
            command_entered = True
            if isinstance(group, HeatingGroup):
                group.set_boost_duration(args.group_boost_duration)
            else:
                logger.error("Group %s isn't a HEATING group", g.id)

    if args.rules:
        command_entered = False
        rules = []
        for argrule in args.rules:
            if argrule == "*":
                rules = home.rules
                break
            else:
                r = home.search_rule_by_id(argrule)
                if r == None:
                    logger.error("Could not find automation rule %s", argrule)
                else:
                    rules.append(r)

        for rule in rules:
            if args.rule_activation is not None:
                if isinstance(rule, SimpleRule):
                    rule.set_rule_enabled_state(args.rule_activation)
                    command_entered = True
                else:
                    logger.error(
                        "can't enable/disable rule %s of type %s",
                        rule.id,
                        rule.ruleType,
                    )

    if args.list_events:
        command_entered = True
        home.onEvent += printEvents
        home.enable_events()
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            return

    if not command_entered:
        parser.print_help()
示例#18
0
class HmIP(object):
    def __init__(self):
        self.config = homematicip.load_config_file(
            config_file=path.join(app.instance_path, 'config.ini'))
        self.home = Home()
        self.home.set_auth_token(self.config.auth_token)
        self.home.init(self.config.access_point)

    def fetch_metrics(self):
        if not self.home.get_current_state():
            self.home.init(self.config.access_point)
            self.home.get_current_state()
        for group in self.home.groups:
            if group.groupType == 'META':
                for device in group.devices:
                    if isinstance(device, WallMountedThermostatPro):
                        self.__collect_thermostat_metrics(group.label, device)
                    elif isinstance(device, ShutterContact):
                        self.__collect_shutter_metrics(group.label, device)
                    elif isinstance(device, TemperatureHumiditySensorOutdoor):
                        self.__collect_thermostat_outdoor_metrics(
                            group.label, device)

    def __collect_shutter_metrics(self, room, device):
        rrd = path.join(app.instance_path, 'rrds', room, f'{device.label}.rrd')
        if not path.exists(rrd):
            makedirs(path.join(app.instance_path, 'rrds', room),
                     mode=0o0750,
                     exist_ok=True)
            rrdtool.create(rrd, '--start', 'now', '--step', '180',
                           'DS:state:GAUGE:540:0:1',
                           'RRA:AVERAGE:0.5:1:360000')
        app.logger.debug('room: {}, label: {}, windowState: {}'.format(
            room, device.label, device.windowState))
        try:
            rrdtool.update(
                path.join(app.instance_path, 'rrds', room,
                          f'{device.label}.rrd'),
                f'N: {self.__window_state(device.windowState)}')
        except rrdtool.OperationalError:
            app.logger.error('room: {}, label: {}, windowState: {}'.format(
                room, device.label, device.windowState))

    @staticmethod
    def __collect_thermostat_metrics(room, device):
        rrd = path.join(app.instance_path, 'rrds', room, f'{device.label}.rrd')
        if not path.exists(rrd):
            makedirs(path.join(app.instance_path, 'rrds', room),
                     mode=0o0750,
                     exist_ok=True)
            rrdtool.create(rrd, '--start', 'now', '--step', '180',
                           'DS:actualtemperature:GAUGE:540:0:50',
                           'DS:settemperature:GAUGE:540:0:40',
                           'DS:humidity:GAUGE:540:0:100',
                           'DS:vapor:GAUGE:540:0:100',
                           'RRA:AVERAGE:0.5:1:360000')
        app.logger.debug(
            f'room: {room}, label: {device.label}, temperature_actual: {device.actualTemperature}, temperature_setpoint: '
            f'{device.setPointTemperature}, humidity_actual: {device.humidity} vaporAmount: {device.vaporAmount}'
        )
        try:
            rrdtool.update(
                path.join(app.instance_path, 'rrds', room,
                          f'{device.label}.rrd'),
                f'N: {device.actualTemperature}:'
                f'{device.setPointTemperature}:'
                f'{device.humidity}:{device.vaporAmount}')
        except rrdtool.OperationalError:
            app.logger.error(
                f'room: {room}, label: {device.label}, temperature_actual: {device.actualTemperature}, temperature_setpoint: '
                f'{device.setPointTemperature}, humidity_actual: {device.humidity} vaporAmount: {device.vaporAmount}'
            )

    @staticmethod
    def __collect_thermostat_outdoor_metrics(room, device):
        rrd = path.join(app.instance_path, 'rrds', room, f'{device.label}.rrd')
        if not path.exists(rrd):
            makedirs(path.join(app.instance_path, 'rrds', room),
                     mode=0o0750,
                     exist_ok=True)
            rrdtool.create(rrd, '--start', 'now', '--step', '180',
                           'DS:actualtemperature:GAUGE:540:-20:55',
                           'DS:humidity:GAUGE:540:0:100',
                           'DS:vapor:GAUGE:540:0:100',
                           'RRA:AVERAGE:0.5:1:360000')
        app.logger.debug(
            f'room: {room}, label: {device.label}, temperature_actual: {device.actualTemperature}, humidity_actual: {device.humidity} '
            f'vaporAmount: {device.vaporAmount}')
        try:
            rrdtool.update(
                path.join(app.instance_path, 'rrds', room,
                          f'{device.label}.rrd'),
                f'N: {device.actualTemperature}:'
                f'{device.humidity}:{device.vaporAmount}')
        except rrdtool.OperationalError:
            app.logger.error(
                f'room: {room}, label: {device.label}, temperature_actual: {device.actualTemperature}, humidity_actual: {device.humidity} '
                f'vaporAmount: {device.vaporAmount}')

    @staticmethod
    def __window_state(state):
        return 1 if state == 'OPEN' else 0

    def convert_to_time_ms(self, timestamp):
        return 1000 * self.convert_to_time_s(timestamp)

    @staticmethod
    def convert_to_time_s(timestamp):
        return timegm(
            datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ').timetuple())

    def get_metric_names(self):
        ret = set()
        for group in self.home.groups:
            if group.groupType == 'META':
                for device in group.devices:
                    if isinstance(device, WallMountedThermostatPro):
                        ret.add('actualtemperature')
                        ret.add('settemperature')
                        ret.add('humidity')
                        ret.add('vapor')
                    elif isinstance(device, ShutterContact):
                        ret.add('state')
                    elif isinstance(device, TemperatureHumiditySensorOutdoor):
                        ret.add('actualtemperature')
                        ret.add('humidity')
                        ret.add('vapor')
        return ret

    def get_metrics(self, start, end, resolution, metrics):
        ret = []
        for root, dirs, files in walk(path.join(app.instance_path, 'rrds')):
            for file in files:
                if file.endswith('.rrd'):
                    rrd = path.join(root, file)
                    app.logger.debug(f'open rrd: {rrd}')
                    fetch = rrdtool.fetch(rrd, 'AVERAGE', '--resolution',
                                          resolution, '--start',
                                          str(self.convert_to_time_s(start)),
                                          '--end',
                                          str(self.convert_to_time_s(end)))
                    for num, name in enumerate(fetch[1]):
                        if name in metrics:
                            datapoints = []
                            ts = fetch[0][0]
                            for dp in fetch[2]:
                                datapoints.append([dp[num], ts * 1000])
                                ts += fetch[0][2]
                            ret.append({
                                'target': file.split('.')[0],
                                'datapoints': datapoints
                            })
        return ret