From 984fc55b208eb60ab6600652ae62ab172059a609 Mon Sep 17 00:00:00 2001 From: Florian Brinker Date: Sun, 12 Jul 2020 02:06:15 +0200 Subject: [PATCH] Update --- config/alerts/windows.yaml | 15 + config/alexa.yaml | 12 + config/automations/landroid.yaml | 25 ++ config/automations/misc.yaml | 34 ++ config/lights.yaml | 7 +- config/sensors/social.yaml | 42 +-- config/switches/misc.yaml | 11 +- config/views/lights.yaml | 21 +- configuration.yaml | 49 +-- .../reolink_dev/ReolinkPyPi/__init__.py | 1 + .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 203 bytes .../__pycache__/camera.cpython-37.pyc | Bin 0 -> 7282 bytes .../reolink_dev/ReolinkPyPi/camera.py | 278 ++++++++++++++++ custom_components/reolink_dev/__init__.py | 1 + .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 191 bytes .../__pycache__/camera.cpython-37.pyc | Bin 0 -> 10496 bytes custom_components/reolink_dev/camera.py | 312 ++++++++++++++++++ custom_components/reolink_dev/manifest.json | 8 + custom_components/reolink_dev/services.yaml | 41 +++ packages/landroid.yaml | 32 +- secrets.yaml.skel | 23 +- 21 files changed, 848 insertions(+), 64 deletions(-) create mode 100644 config/automations/landroid.yaml create mode 100644 config/automations/misc.yaml create mode 100644 custom_components/reolink_dev/ReolinkPyPi/__init__.py create mode 100644 custom_components/reolink_dev/ReolinkPyPi/__pycache__/__init__.cpython-37.pyc create mode 100644 custom_components/reolink_dev/ReolinkPyPi/__pycache__/camera.cpython-37.pyc create mode 100644 custom_components/reolink_dev/ReolinkPyPi/camera.py create mode 100644 custom_components/reolink_dev/__init__.py create mode 100644 custom_components/reolink_dev/__pycache__/__init__.cpython-37.pyc create mode 100644 custom_components/reolink_dev/__pycache__/camera.cpython-37.pyc create mode 100644 custom_components/reolink_dev/camera.py create mode 100644 custom_components/reolink_dev/manifest.json create mode 100644 custom_components/reolink_dev/services.yaml diff --git a/config/alerts/windows.yaml b/config/alerts/windows.yaml index 79d32ba..4d495d3 100644 --- a/config/alerts/windows.yaml +++ b/config/alerts/windows.yaml @@ -22,6 +22,21 @@ attic_window_open: repeat: 30 can_acknowledge: true skip_first: true + notifiers: + - telegram_group + - alexa_all + +garage_door_open: + name: Garagentor geöffnet + message: "Zur Info - Die *Garage* steht noch *offen*!" + done_message: "Zur Info - Die *Garage* ist wieder *geschlossen*." + entity_id: binary_sensor.lumi_garage_door + state: "on" + repeat: + - 10 + - 30 + can_acknowledge: true + skip_first: true notifiers: - telegram_group - alexa_all \ No newline at end of file diff --git a/config/alexa.yaml b/config/alexa.yaml index 6df6d61..cd3cc27 100644 --- a/config/alexa.yaml +++ b/config/alexa.yaml @@ -9,6 +9,7 @@ - light.kuchen_theke - light.esstisch - light.office + - light.onair - switch.livingroom_stimmungslicht - switch.livingroom_music - switch.livingroom_netflix @@ -19,6 +20,8 @@ - switch.desktop_wol - switch.wallboard_display - switch.tplink1 + - switch.osram_plug_01_57b6060a_on_off + - switch.onair_lamp_recording # include_domains: # - switch # exclude_entities: @@ -43,6 +46,9 @@ light.stimmungslicht: name: Stimmungslicht description: Wohnzimmer - Stimmungslicht + light.onair: + name: Studio-Treppe + description: Studio-Treppenlicht switch.livingroom_music: name: Musik description: Wohnzimmer - Musik @@ -70,4 +76,10 @@ switch.tplink1: name: Kamera description: Wohnzimmer Kamera + switch.osram_plug_01_57b6060a_on_off: + name: Ring + description: Studio-Steckdose + switch.onair_lamp_recording: + name: Aufnahme + description: Studio-Treppenlicht Aufnahme-Modus # ACHTUNG: WHITELIST EBENFALLS ERGÄNZEN! \ No newline at end of file diff --git a/config/automations/landroid.yaml b/config/automations/landroid.yaml new file mode 100644 index 0000000..493bb2b --- /dev/null +++ b/config/automations/landroid.yaml @@ -0,0 +1,25 @@ +- alias: Landroid mowing + trigger: + - platform: state + entity_id: sensor.landroid_hans_dieter_status + to: "Mowing" + action: + - service: notify.telegram_group + data_template: + message: "Achtung - *Hans-Dieter* *mäht* jetzt den Rasen!" + - service: notify.alexa_all + data_template: + message: "Achtung - Hans-Dieter maeht jetzt den Rasen!" + +- alias: Landroid home + trigger: + - platform: state + entity_id: sensor.landroid_hans_dieter_status + to: "Home" + action: + - service: notify.telegram_group + data_template: + message: "Zur Info - *Hans-Dieter* ist nun wieder in seiner *Ladestation*." + - service: notify.alexa_all + data_template: + message: "Zur Info - Hans-Dieter ist nun wieder in seiner Ladestation." \ No newline at end of file diff --git a/config/automations/misc.yaml b/config/automations/misc.yaml new file mode 100644 index 0000000..38bc363 --- /dev/null +++ b/config/automations/misc.yaml @@ -0,0 +1,34 @@ +- alias: Instagram Counter - Adjust Brightness + trigger: + platform: state + entity_id: input_number.instagram_counter_brightness + action: + - service: rest_command.instagram_counter_brightness + data_template: + value: "{{ trigger.to_state.state | int }}" + +- alias: onAir Recording On + trigger: + platform: state + entity_id: input_boolean.onair_lamp_recording + to: 'on' + action: + - service: light.turn_on + data: + entity_id: light.onair + rgb_color: [255, 0, 0] + +- alias: onAir Recording Off + trigger: + platform: state + entity_id: input_boolean.onair_lamp_recording + to: 'off' + action: + - service: light.turn_on + data: + entity_id: light.onair + rgb_color: [255, 255, 255] + - service: light.turn_on + data: + entity_id: light.onair + color_temp: 367 diff --git a/config/lights.yaml b/config/lights.yaml index ae1a80c..aa2888b 100644 --- a/config/lights.yaml +++ b/config/lights.yaml @@ -4,4 +4,9 @@ hdmi_priority: 900 - platform: switch name: Stimmungslicht - entity_id: switch.livingroom_stimmungslicht \ No newline at end of file + entity_id: switch.livingroom_stimmungslicht + - platform: group + name: onAir + entities: + - light.innr_gu10_rgb_1 + - light.innr_gu10_rgb_2 \ No newline at end of file diff --git a/config/sensors/social.yaml b/config/sensors/social.yaml index 28ba954..4a6e53e 100644 --- a/config/sensors/social.yaml +++ b/config/sensors/social.yaml @@ -77,20 +77,20 @@ scan_interval: 300 name: instagram_beauty resource: !secret instagram_beauty - value_template: '{{ value_json.data.counts.followed_by }}' + value_template: '{{ value_json.followers_count }}' unit_of_measurement: Followers force_update: true - platform: rest scan_interval: 900 name: instagram_beauty_follows resource: !secret instagram_beauty - value_template: '{{ value_json.data.counts.follows }}' + value_template: '{{ value_json.follows_count }}' force_update: true - platform: rest scan_interval: 600 name: instagram_beauty_media resource: !secret instagram_beauty - value_template: '{{ value_json.data.counts.media }}' + value_template: '{{ value_json.media_count }}' force_update: true # franky @@ -98,20 +98,20 @@ scan_interval: 300 name: instagram_franky resource: !secret instagram_franky - value_template: '{{ value_json.data.counts.followed_by }}' + value_template: '{{ value_json.followers_count }}' unit_of_measurement: Followers force_update: true - platform: rest scan_interval: 900 name: instagram_franky_follows resource: !secret instagram_franky - value_template: '{{ value_json.data.counts.follows }}' + value_template: '{{ value_json.follows_count }}' force_update: true - platform: rest scan_interval: 600 name: instagram_franky_media resource: !secret instagram_franky - value_template: '{{ value_json.data.counts.media }}' + value_template: '{{ value_json.media_count }}' force_update: true # fb @@ -119,20 +119,20 @@ scan_interval: 300 name: instagram_fb resource: !secret instagram_fb - value_template: '{{ value_json.data.counts.followed_by }}' + value_template: '{{ value_json.followers_count }}' unit_of_measurement: Followers force_update: true - platform: rest scan_interval: 900 name: instagram_fb_follows resource: !secret instagram_fb - value_template: '{{ value_json.data.counts.follows }}' + value_template: '{{ value_json.follows_count }}' force_update: true - platform: rest scan_interval: 600 name: instagram_fb_media resource: !secret instagram_fb - value_template: '{{ value_json.data.counts.media }}' + value_template: '{{ value_json.media_count }}' force_update: true # mtb @@ -140,20 +140,20 @@ scan_interval: 300 name: instagram_mtb resource: !secret instagram_mtb - value_template: '{{ value_json.data.counts.followed_by }}' + value_template: '{{ value_json.followers_count }}' unit_of_measurement: Followers force_update: true - platform: rest scan_interval: 900 name: instagram_mtb_follows resource: !secret instagram_mtb - value_template: '{{ value_json.data.counts.follows }}' + value_template: '{{ value_json.follows_count }}' force_update: true - platform: rest scan_interval: 600 name: instagram_mtb_media resource: !secret instagram_mtb - value_template: '{{ value_json.data.counts.media }}' + value_template: '{{ value_json.media_count }}' force_update: true # medieval @@ -161,20 +161,20 @@ scan_interval: 300 name: instagram_medieval resource: !secret instagram_medieval - value_template: '{{ value_json.data.counts.followed_by }}' + value_template: '{{ value_json.followers_count }}' unit_of_measurement: Followers force_update: true - platform: rest scan_interval: 900 name: instagram_medieval_follows resource: !secret instagram_medieval - value_template: '{{ value_json.data.counts.follows }}' + value_template: '{{ value_json.follows_count }}' force_update: true - platform: rest scan_interval: 600 name: instagram_medieval_media resource: !secret instagram_medieval - value_template: '{{ value_json.data.counts.media }}' + value_template: '{{ value_json.media_count }}' force_update: true # lotte @@ -182,20 +182,20 @@ scan_interval: 300 name: instagram_lotte resource: !secret instagram_lotte - value_template: '{{ value_json.data.counts.followed_by }}' + value_template: '{{ value_json.followers_count }}' unit_of_measurement: Followers force_update: true - platform: rest scan_interval: 900 name: instagram_lotte_follows resource: !secret instagram_lotte - value_template: '{{ value_json.data.counts.follows }}' + value_template: '{{ value_json.follows_count }}' force_update: true - platform: rest scan_interval: 600 name: instagram_lotte_media resource: !secret instagram_lotte - value_template: '{{ value_json.data.counts.media }}' + value_template: '{{ value_json.media_count }}' force_update: true # codedwithlove @@ -203,20 +203,20 @@ scan_interval: 300 name: instagram_codedwithlove resource: !secret instagram_codedwithlove - value_template: '{{ value_json.data.counts.followed_by }}' + value_template: '{{ value_json.followers_count }}' unit_of_measurement: Followers force_update: true - platform: rest scan_interval: 900 name: instagram_codedwithlove_follows resource: !secret instagram_codedwithlove - value_template: '{{ value_json.data.counts.follows }}' + value_template: '{{ value_json.follows_count }}' force_update: true - platform: rest scan_interval: 600 name: instagram_codedwithlove_media resource: !secret instagram_codedwithlove - value_template: '{{ value_json.data.counts.media }}' + value_template: '{{ value_json.media_count }}' force_update: true # TikTok diff --git a/config/switches/misc.yaml b/config/switches/misc.yaml index 8768cf5..a3598b3 100644 --- a/config/switches/misc.yaml +++ b/config/switches/misc.yaml @@ -12,4 +12,13 @@ port: !secret nas_ssh_port command_or_param: !secret desktop_mac turn_off: - service: script.dummy \ No newline at end of file + service: script.dummy + + onair_lamp_recording: + value_template: "{{ is_state('input_boolean.onair_lamp_recording', 'on') }}" + turn_on: + - service: input_boolean.turn_on + entity_id: input_boolean.onair_lamp_recording + turn_off: + - service: input_boolean.turn_off + entity_id: input_boolean.onair_lamp_recording \ No newline at end of file diff --git a/config/views/lights.yaml b/config/views/lights.yaml index ffe3586..e28efea 100644 --- a/config/views/lights.yaml +++ b/config/views/lights.yaml @@ -15,4 +15,23 @@ cards: name: Ambilight - type: light entity: light.esstisch - name: Esstisch \ No newline at end of file + name: Esstisch + - type: light + entity: light.tint_rgb_gu10_1 + name: Kinderbad + + - type: vertical-stack + title: Studio + cards: + - type: light + entity: light.onair + name: Studio-Treppe + - type: entities + show_header_toggle: false + entities: + - entity: switch.onair_lamp_recording + name: Studio Aufnahme + icon: mdi:camera-rear + - entity: switch.osram_plug_01_57b6060a_on_off + name: Studio Ringlicht + icon: mdi:checkbox-blank-circle-outline \ No newline at end of file diff --git a/configuration.yaml b/configuration.yaml index 6c7f535..1b35d65 100644 --- a/configuration.yaml +++ b/configuration.yaml @@ -35,7 +35,7 @@ http: ip_ban_enabled: true login_attempts_threshold: 5 use_x_forwarded_for: true - base_url: https://hass.f-brinker.de + base_url: !secret url_base trusted_proxies: - 127.0.0.1 - ::1 @@ -58,7 +58,7 @@ zha: emulated_roku: servers: - name: Home Assistant - listen_port: 8060 + listen_port: !secret roku_port mqtt: broker: !secret mqtt_broker_ip @@ -87,12 +87,6 @@ notify: - name: telegram_fb platform: telegram chat_id: !secret telegram_chat_fb - - platform: command_line - name: alexa_kitchen - command: "/config/alexa_wrapper.sh -d 'Küche'" - - platform: command_line - name: alexa_livingroom - command: "/config/alexa_wrapper.sh -d 'Wohnzimmer'" - platform: command_line name: alexa_all command: "/config/alexa_wrapper.sh -d 'ALL'" @@ -141,10 +135,23 @@ ffmpeg: ffmpeg_bin: /usr/bin/ffmpeg input_datetime: - bedroom_alarm_clock_time: - name: Wecker - has_date: false - has_time: true + bedroom_alarm_clock_time: + name: Wecker + has_date: false + has_time: true + +input_number: + instagram_counter_brightness: + name: Instagram Counter Brightness + initial: 15 + min: 0 + max: 15 + step: 1 + +input_boolean: + onair_lamp_recording: + name: onAir Recording Status + initial: false alarm_control_panel: - platform: manual @@ -152,22 +159,26 @@ alarm_control_panel: code: !secret alarm_code code_arm_required: true delay_time: 20 - pending_time: 30 + arming_time: 30 trigger_time: 120 disarm_after_trigger: false disarmed: trigger_time: 0 armed_home: - pending_time: 0 + arming_time: 0 delay_time: 0 armed_night: - pending_time: 0 + arming_time: 0 delay_time: 0 shell_command: ssh: 'ssh -o "StrictHostKeyChecking=no" -i {{ sshkey }} {{ host }} -l {{ user }} -p {{ port }} {{ command_or_param }}' rest_command: + instagram_counter_brightness: + url: !secret url_instagram_counter_brightness + method: GET + payload: 'value={{ value }}' shinobi_monitorstates: url: "https://{{ host }}/{{ apikey }}/monitorStates/{{ group }}/{{ preset_name }}" @@ -185,10 +196,10 @@ spotify: client_id: !secret spotify_client_id client_secret: !secret spotify_client_secret -tplink: - discovery: false - switch: - - host: !secret tplink_ip +#tplink: +# discovery: false +# switch: +# - host: !secret tplink_ip # External config files alert: !include_dir_merge_named config/alerts/ diff --git a/custom_components/reolink_dev/ReolinkPyPi/__init__.py b/custom_components/reolink_dev/ReolinkPyPi/__init__.py new file mode 100644 index 0000000..7461c90 --- /dev/null +++ b/custom_components/reolink_dev/ReolinkPyPi/__init__.py @@ -0,0 +1 @@ +"""Reolink Camera component for HomeAssistant.""" \ No newline at end of file diff --git a/custom_components/reolink_dev/ReolinkPyPi/__pycache__/__init__.cpython-37.pyc b/custom_components/reolink_dev/ReolinkPyPi/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e655c5c7cc6ca3c1e5081c190a7a189294d97f31 GIT binary patch literal 203 zcmZ?b<>g`kf_zVzI71-)7{q}AMj*ohh>JOZL<&O`LkeRsgCa(-?>eqL%`i9%X_k%C8lZmMH(ab|HzVqS@!pC;oi_W1ae{N(ufl?+8pK$F14 zFI)ZO{JgZxbp7Pg;*$K_c(@_O`b7}q<5N=0^r2P-R0d?~$H!;pWtPOp>lIYq;;_lh QPbtkwwF5cwGY~TX0Alw!Pyhe` literal 0 HcmV?d00001 diff --git a/custom_components/reolink_dev/ReolinkPyPi/__pycache__/camera.cpython-37.pyc b/custom_components/reolink_dev/ReolinkPyPi/__pycache__/camera.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2dde65b626f14236e3b22b78d18f15c91d520c15 GIT binary patch literal 7282 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 T2lP6LFrqBkz=a6^w2Jm0p=Wc~ literal 0 HcmV?d00001 diff --git a/custom_components/reolink_dev/ReolinkPyPi/camera.py b/custom_components/reolink_dev/ReolinkPyPi/camera.py new file mode 100644 index 0000000..67d0f2a --- /dev/null +++ b/custom_components/reolink_dev/ReolinkPyPi/camera.py @@ -0,0 +1,278 @@ +""" +Reolink Camera API +""" +import requests +import datetime +import json +import logging + +_LOGGER = logging.getLogger(__name__) + +class ReolinkApi(object): + def __init__(self, ip, channel): + self._url = "http://" + ip + "/cgi-bin/api.cgi" + self._ip = ip + self._channel = channel + self._token = None + self._motion_state = False + self._last_motion = 0 + self._device_info = None + self._motion_state = None + self._ftp_state = None + self._email_state = None + self._ir_state = None + self._rtspport = None + self._rtmpport = None + self._ptzpresets = dict() + + def status(self): + if self._token is None: + return + + param_channel = {"channel": self._channel} + body = [{"cmd": "GetDevInfo", "action":1, "param": param_channel}, + {"cmd": "GetNetPort", "action": 1, "param": param_channel}, + {"cmd": "GetFtp", "action": 1, "param": param_channel}, + {"cmd": "GetEmail", "action": 1, "param": param_channel}, + {"cmd": "GetIrLights", "action": 1, "param": param_channel}, + {"cmd": "GetPtzPreset", "action": 1, "param": param_channel}] + + param = {"token": self._token} + response = self.send(body, param) + + try: + json_data = json.loads(response.text) + except: + _LOGGER.error(f"Error translating response to json") + return + + for data in json_data: + try: + if data["cmd"] == "GetDevInfo": + self._device_info = data + + elif data["cmd"] == "GetNetPort": + self._netport_settings = data + self._rtspport = data["value"]["NetPort"]["rtspPort"] + self._rtmpport = data["value"]["NetPort"]["rtmpPort"] + + elif data["cmd"] == "GetFtp": + self._ftp_settings = data + if (data["value"]["Ftp"]["schedule"]["enable"] == 1): + self._ftp_state = True + else: + self._ftp_state = False + + elif data["cmd"] == "GetEmail": + self._email_settings = data + if (data["value"]["Email"]["schedule"]["enable"] == 1): + self._email_state = True + else: + self._email_state = False + + elif data["cmd"] == "GetIrLights": + self._ir_settings = data + if (data["value"]["IrLights"]["state"] == "Auto"): + self._ir_state = True + else: + self._ir_state = False + + elif data["cmd"] == "GetPtzPreset": + self._ptzpresets_settings = data + for preset in data["value"]["PtzPreset"]: + if int(preset["enable"]) == 1: + preset_name = preset["name"] + preset_id = int(preset["id"]) + self._ptzpresets[preset_name] = preset_id + _LOGGER.debug(f"Got preset {preset_name} with ID {preset_id}") + else: + _LOGGER.debug(f"Preset is not enabled: {preset}") + except: + continue + + @property + def motion_state(self): + body = [{"cmd": "GetMdState", "action": 0, "param":{"channel":self._channel}}] + param = {"token": self._token} + + response = self.send(body, param) + + try: + json_data = json.loads(response.text) + + if json_data is None: + _LOGGER.error(f"Unable to get Motion detection state at IP {self._ip}") + self._motion_state = False + return self._motion_state + + if json_data[0]["value"]["state"] == 1: + self._motion_state = True + self._last_motion = datetime.datetime.now() + else: + self._motion_state = False + except: + self._motion_state = False + + return self._motion_state + + @property + def still_image(self): + response = self.send(None, f"?cmd=Snap&channel={self._channel}&token={self._token}", stream=True) + response.raw.decode_content = True + return response.raw + + @property + def snapshot(self): + response = self.send(None, f"?cmd=Snap&channel={self._channel}&token={self._token}", stream=False) + return response.content + + @property + def ftp_state(self): + return self._ftp_state + + @property + def email_state(self): + return self._email_state + + @property + def ir_state(self): + return self._ir_state + + @property + def rtmpport(self): + return self._rtmpport + + @property + def rtspport(self): + return self._rtspport + + @property + def last_motion(self): + return self._last_motion + + @property + def ptzpresets(self): + return self._ptzpresets + + def login(self, username, password): + body = [{"cmd": "Login", "action": 0, "param": {"User": {"userName": username, "password": password}}}] + param = {"cmd": "Login", "token": "null"} + + response = self.send(body, param) + + try: + json_data = json.loads(response.text) + except: + _LOGGER.error(f"Error translating login response to json") + return + + if json_data is not None: + if json_data[0]["code"] == 0: + self._token = json_data[0]["value"]["Token"]["name"] + _LOGGER.info(f"Reolink camera logged in at IP {self._ip}") + else: + _LOGGER.error(f"Failed to login at IP {self._ip}. No token available") + else: + _LOGGER.error(f"Failed to login at IP {self._ip}. Connection error.") + + def logout(self): + body = [{"cmd":"Logout","action":0,"param":{}}] + param = {"cmd": "Logout", "token": self._token} + + self.send(body, param) + + def set_ftp(self, enabled): + self.status() + + if not self._ftp_settings: + _LOGGER.error("Error while fetching current FTP settings") + return + + if enabled == True: + newValue = 1 + else: + newValue = 0 + + body = [{"cmd":"SetFtp","action":0,"param": self._ftp_settings["value"] }] + body[0]["param"]["Ftp"]["schedule"]["enable"] = newValue + + response = self.send(body, {"cmd": "SetFtp", "token": self._token} ) + try: + json_data = json.loads(response.text) + if json_data[0]["value"]["rspCode"] == 200: + return True + else: + return False + except: + _LOGGER.error(f"Error translating FTP response to json") + return False + + def set_email(self, enabled): + self.status() + + if not self._email_settings: + _LOGGER.error("Error while fetching current email settings") + return + + if enabled == True: + newValue = 1 + else: + newValue = 0 + + body = [{"cmd":"SetEmail","action":0,"param": self._email_settings["value"] }] + body[0]["param"]["Email"]["schedule"]["enable"] = newValue + + response = self.send(body, {"cmd": "SetEmail", "token": self._token} ) + try: + json_data = json.loads(response.text) + if json_data[0]["value"]["rspCode"] == 200: + return True + else: + return False + except: + _LOGGER.error(f"Error translating Email response to json") + return False + + def set_ir_lights(self, enabled): + self.status() + + if not self._ir_settings: + _LOGGER.error("Error while fetching current IR light settings") + return + + if enabled == True: + newValue = "Auto" + else: + newValue = "Off" + + body = [{"cmd":"SetIrLights","action":0,"param": self._ir_settings["value"] }] + body[0]["param"]["IrLights"]["state"] = newValue + + response = self.send(body, {"cmd": "SetIrLights", "token": self._token} ) + try: + json_data = json.loads(response.text) + if json_data[0]["value"]["rspCode"] == 200: + return True + else: + return False + except requests.exceptions.RequestException: + _LOGGER.error(f"Error translating IR Lights response to json") + return False + + def send(self, body, param, stream=False): + try: + if (self._token is None and + (body is None or body[0]["cmd"] != "Login")): + _LOGGER.info(f"Reolink camera at IP {self._ip} is not logged in") + return + + if body is None: + response = requests.get(self._url, params=param, stream=stream) + else: + response = requests.post(self._url, data=json.dumps(body), params=param) + + return response + except Exception: + _LOGGER.error(f"Exception while calling Reolink camera API at ip {self._ip}") + return None + diff --git a/custom_components/reolink_dev/__init__.py b/custom_components/reolink_dev/__init__.py new file mode 100644 index 0000000..7461c90 --- /dev/null +++ b/custom_components/reolink_dev/__init__.py @@ -0,0 +1 @@ +"""Reolink Camera component for HomeAssistant.""" \ No newline at end of file diff --git a/custom_components/reolink_dev/__pycache__/__init__.cpython-37.pyc b/custom_components/reolink_dev/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61393d381d42a232d701b09b491965d6c2b77068 GIT binary patch literal 191 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 30): + self._hass.loop.create_task(self.update_status()) + + except Exception as ex: + _LOGGER.error("Got exception while fetching the state: %s", ex) + + def disconnect(self, event): + _LOGGER.info("Disconnecting from Reolink camera") + self._reolinkSession.logout() diff --git a/custom_components/reolink_dev/manifest.json b/custom_components/reolink_dev/manifest.json new file mode 100644 index 0000000..850d570 --- /dev/null +++ b/custom_components/reolink_dev/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "reolink_dev", + "name": "Reolink IP camera", + "documentation": "https://www.example.com", + "dependencies": ["ffmpeg"], + "codeowners": ["@fwestenberg"], + "requirements": ["aiosmtpd==1.2"] + } diff --git a/custom_components/reolink_dev/services.yaml b/custom_components/reolink_dev/services.yaml new file mode 100644 index 0000000..d7762fc --- /dev/null +++ b/custom_components/reolink_dev/services.yaml @@ -0,0 +1,41 @@ +enable_ftp: + description: Enable FTP upload on motion recording. + fields: + entity_id: + description: Name of the Reolink camera entity to set. + example: 'camera.frontdoor' + +disable_ftp: + description: Disable FTP upload on motion recording. + fields: + entity_id: + description: Name of the Reolink camera entity to set. + example: 'camera.frontdoor' + +enable_email: + description: Enable email functionality on motion detection. + fields: + entity_id: + description: Name of the Reolink camera entity to set. + example: 'camera.frontdoor' + +disable_email: + description: Disable email functionality on motion detection. + fields: + entity_id: + description: Name of the Reolink camera entity to set. + example: 'camera.frontdoor' + +enable_ir_lights: + description: Enable the infrared lights (nightvision) of the Reolink camera. + fields: + entity_id: + description: Name of the Reolink camera entity to set. + example: 'camera.frontdoor' + +disable_ir_lights: + description: Disable the infrared lights (nightvision) of the Reolink camera. + fields: + entity_id: + description: Name of the Reolink camera entity to set. + example: 'camera.frontdoor' \ No newline at end of file diff --git a/packages/landroid.yaml b/packages/landroid.yaml index 1a7b637..553c9bd 100644 --- a/packages/landroid.yaml +++ b/packages/landroid.yaml @@ -212,21 +212,21 @@ input_boolean: # Automations ####################################################### automation: - - id: "landroid_status_notify" - alias: "Landroid Status Notification" - initial_state: true - trigger: - - platform: state - entity_id: sensor.landroid_hans_dieter_status - condition: - - condition: template - value_template: "{{ trigger.to_state.state != trigger.from_state.state }}" - action: - - service: persistent_notification.create - data_template: - title: Lanroid Status - message: "{{ trigger.from_state.state }} -> {{ trigger.to_state.state }} - {{ states('sensor.date_time') }}" - +# - id: "landroid_status_notify" +# alias: "Landroid Status Notification" +# initial_state: true +# trigger: +# - platform: state +# entity_id: sensor.landroid_hans_dieter_status +# condition: +# - condition: template +# value_template: "{{ trigger.to_state.state != trigger.from_state.state }}" +# action: +# - service: persistent_notification.create +# data_template: +# title: Landroid Status +# message: "{{ trigger.from_state.state }} -> {{ trigger.to_state.state }} - {{ states('sensor.date_time') }}" +# - id: "landroid_error_notify" alias: "Landroid Error Notification" initial_state: true @@ -239,7 +239,7 @@ automation: action: - service: persistent_notification.create data_template: - title: Lanroid Status + title: Landroid Status message: "{{ trigger.from_state.state }} -> {{ trigger.to_state.state }} - {{ states('sensor.date_time') }}" # Scripts ########################################################### diff --git a/secrets.yaml.skel b/secrets.yaml.skel index c279a29..e08d169 100644 --- a/secrets.yaml.skel +++ b/secrets.yaml.skel @@ -8,12 +8,18 @@ adbkey: alexa_email: alexa_password: +url_base: + url_chronograf: url_esphome: url_haslave_livingroom: url_haslave_office: +url_instagram_counter_brightness: + +roku_port: + # Zones home_lat: home_long: @@ -56,6 +62,13 @@ cam_livingroom_ip: cam_livingroom_user: cam_livingroom_password: +# Robots +landroid_mail: +landroid_pass: +landroid_ip: +landroid_sn: +landroid_mac: + # Weather openweathermap: @@ -84,17 +97,16 @@ telegram_chat_fb: telegram_chat_group: # Social data -# invite @ https: -# accept @ https: -# wait a while so instagram registers that we are a sandbox user now... -# open and authorize https: +# App https: +# Login & Copy the Instagram URLs https: instagram_beauty: instagram_franky: + instagram_fb: instagram_mtb: +instagram_codedwithlove: instagram_medieval: instagram_lotte: -instagram_codedwithlove: youtube_beauty: youtube_mtb: @@ -103,3 +115,4 @@ bitly_blog_bb: bitly_instagram_bb: bitly_impressum_bb: bitly_youtube_bb: +