diff --git a/README.md b/README.md
index 24dec20..cf91368 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,10 @@
# 使用说明
-1、将下载的插件中两个文件夹复制到custom_components目录下
-2、key和secret请在萤石开发网站获取,具体可详见https://bbs.hassbian.com/thread-7062-1-1.html
-3、在configuration.yaml文件中添加以下内容启用插件
-~~~
-ezvizctrl:
- deviceSerial: ****设备序列号
- appKey: ****api接口里面的appkey
- appSecret: ****api接口里面的appsecret
+1. 将下载的插件中的`ezviz`文件夹复制到`custom_components`目录下
+2. `key`和`secret`请在[萤石开发网站](https://bbs.hassbian.com/thread-7062-1-1.html)获取
+3. 在`configuration.yaml`文件中添加以下内容启用插件
+
+```yaml
sensor:
- platform: ezviz
appKey: ****
@@ -15,87 +12,98 @@ sensor:
deviceSerial: ***
scan_interval: 30
options:
+ - sceneStatus
- privacyStatus
- - AlarmStatus
+ - pirStatus
- alarmSoundMode
-~~~
-4、在configuration.yaml添加两个开关,用于修改移动侦测和遮蔽状态
-~~~
+ - defenceStatus
+ - onlineStatus
+ - motionStatus
+```
+
+4. 在`configuration.yaml`添加两个开关,用于修改移动侦测和遮蔽状态
+```yaml
switch:
- platform: template
switches:
- privacy:
+ sence:
friendly_name: 镜头遮蔽
- value_template: "{{ is_state('sensor.ezviz_privacystatus', '启用遮蔽') }}"
+ value_template: "{{ is_state('sensor.ezviz_sceneStatus', '启用遮蔽') }}"
turn_on:
- service: ezvizctrl.enable_privacy
+ service: ezviz.enable_sence
turn_off:
- service: ezvizctrl.disable_privacy
+ service: ezviz.disable_sence
icon_template: >-
- {% if is_state('sensor.ezviz_privacystatus', '启用遮蔽') %}
+ {% if is_state('sensor.ezviz_sceneStatus', '启用遮蔽') %}
mdi:eye-off
{% else %}
mdi:eye
{% endif %}
- platform: template
switches:
- alarm:
- friendly_name: 移动侦测
- value_template: "{{ is_state('sensor.ezviz_alarmstatus', '布防') }}"
+ defence:
+ friendly_name: 布防状态(活动检测)
+ value_template: "{{ is_state('sensor.ezviz_defenceStatus', '布防') }}"
turn_on:
- service: ezvizctrl.enable_alarm
+ service: ezviz.enable_defence
turn_off:
- service: ezvizctrl.disable_alarm
+ service: ezviz.disable_defence
icon_template: >-
- {% if is_state('sensor.ezviz_alarmstatus', '布防') %}
+ {% if is_state('sensor.ezviz_defenceStatus', '布防') %}
mdi:shield-home
{% else %}
mdi:shield-off
{% endif %}
-~~~
-5、在lovelace上面添加控制界面
-首先安装 radial-menu 插件,https://github.com/custom-cards/radial-menu
-将如下代码,通过原始编辑器,在合适的位置添加进去
-~~~
-- cards:
- - entities:
- - switch.privacy
- - switch.alarm
- - sensor.ezviz_alarmsoundmode
- show_header_toggle: false
- title: 摄像机状态
- type: entities
- - default_dismiss: false
- default_open: true
- icon: 'mdi:webcam'
- items:
- - entity: null
- icon: 'mdi:arrow-up-thick'
- name: 上
- tap_action:
- action: call-service
- service: ezvizctrl.up
- - entity: null
- icon: 'mdi:arrow-right-thick'
- name: 右
- tap_action:
- action: call-service
- service: ezvizctrl.right
- - entity: null
- icon: 'mdi:arrow-down-thick'
- name: 下
- tap_action:
- action: call-service
- service: ezvizctrl.down
- - entity: null
- icon: 'mdi:arrow-left-thick'
- name: 左
- tap_action:
- action: call-service
- service: ezvizctrl.left
- name: 家
- type: 'custom:radial-menu'
- type: vertical-stack
-~~~
-6、enjoyit
+```
+5. 安装 [radial-menu](https://github.com/custom-cards/radial-menu) 插件
+6. 将如下代码,通过原始编辑器,在合适的位置添加进去
+```yaml
+ cards:
+ - type: entities
+ entities:
+ - entity: switch.sence
+ - entity: switch.defence
+ - entity: sensor.ezviz_alarmsoundmode
+ name: 告警声音模式
+ - entity: sensor.ezviz_onlinestatus
+ name: 在线状态
+ - entity: sensor.ezviz_privacystatus
+ name: 隐私状态
+ - entity: sensor.ezviz_motionstatus
+ name: 人体感应告警
+ show_header_toggle: false
+ title: 摄像机状态
+ - default_dismiss: false
+ default_open: true
+ icon: 'mdi:webcam'
+ items:
+ - entity: null
+ icon: 'mdi:arrow-up-thick'
+ name: 上
+ tap_action:
+ action: call-service
+ service: ezviz.up
+ - entity: null
+ icon: 'mdi:arrow-right-thick'
+ name: 右
+ tap_action:
+ action: call-service
+ service: ezviz.right
+ - entity: null
+ icon: 'mdi:arrow-down-thick'
+ name: 下
+ tap_action:
+ action: call-service
+ service: ezviz.down
+ - entity: null
+ icon: 'mdi:arrow-left-thick'
+ name: 左
+ tap_action:
+ action: call-service
+ service: ezviz.left
+ name: 家
+ type: 'custom:radial-menu'
+
+ ```
+7. enjoyit
diff --git a/ezviz/__init__.py b/ezviz/__init__.py
new file mode 100755
index 0000000..8b13789
--- /dev/null
+++ b/ezviz/__init__.py
@@ -0,0 +1 @@
+
diff --git a/ezviz/manifest.json b/ezviz/manifest.json
index a2720c3..732f591 100644
--- a/ezviz/manifest.json
+++ b/ezviz/manifest.json
@@ -2,6 +2,7 @@
"domain": "ezviz",
"name": "ezviz",
"documentation": "https://www.example.com",
+ "version":"0.0.1",
"dependencies": [],
"codeowners": [],
"requirements": []
diff --git a/ezviz/sensor.py b/ezviz/sensor.py
index f209c98..01aeeee 100755
--- a/ezviz/sensor.py
+++ b/ezviz/sensor.py
@@ -1,11 +1,10 @@
-import json
import time
-from urllib import request, parse
+import datetime
import logging
-from datetime import timedelta
import voluptuous as vol
-import requests
-
+from requests.exceptions import RequestException
+from requests_futures.sessions import FuturesSession
+
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_FRIENDLY_NAME, TEMP_CELSIUS)
@@ -13,10 +12,10 @@
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import track_time_interval
import homeassistant.util.dt as dt_util
-
+
_LOGGER = logging.getLogger(__name__)
-TIME_BETWEEN_UPDATES = timedelta(seconds=60)
+TIME_BETWEEN_UPDATES = datetime.timedelta(seconds=60)
# 配置文件中平台下的配置项
CONF_APP_KEY = 'appKey'
@@ -26,9 +25,13 @@
# 定义三个可选项
# 格式:配置项名称:[OBJECT_ID, friendly_name, icon, 单位]
OPTIONS = {
- "privacyStatus": ["ezviz_privacyStatus", "遮蔽状态", "", ""],
- "AlarmStatus": ["ezviz_AlarmStatus", "移动侦测", "", ""],
- "alarmSoundMode": ["ezviz_alarmSoundMode", "报警音模式", "mdi:surround-sound", ""],
+ "sceneStatus": ["ezviz_sceneStatus", "遮蔽状态", "mdi:eye-off", ""],
+ "privacyStatus": ["ezviz_privacyStatus", "隐私状态", "mdi:looks", ""],
+ "pirStatus": ["ezviz_pirStatus", "红外状态", "mdi:camcorder-box", ""],
+ "alarmSoundMode": ["ezviz_alarmSoundMode", "告警声音模式", "mdi:surround-sound", ""],
+ "defenceStatus":["ezviz_defenceStatus", "布防状态", "mdi:shield-home", ""],
+ "onlineStatus": ["ezviz_onlineStatus", "在线状态", "mdi:link", ""],
+ "motionStatus": ["ezviz_motionStatus", "人体感应事件", "mdi:walk", ""],
}
ATTR_UPDATE_TIME = "更新时间"
@@ -46,23 +49,24 @@
def setup_platform(hass, config, add_devices, discovery_info=None):
"""根据配置文件,setup_platform函数会自动被系统调用."""
_LOGGER.info("setup platform sensor.ezviz...")
-
+
deviceSerial=config.get(CONF_Device_Serial)
appKey= config.get(CONF_APP_KEY)
appSecret= config.get(CONF_APP_SECRET)
- # 定义一个新的数据对象,用于获取萤石API数据。
+ # 定义一个新的数据对象
data = EZVIZData(hass,deviceSerial,appKey,appSecret)
-
+
# 根据配置文件options中的内容,添加若干个设备
dev = []
for option in config[CONF_OPTIONS]:
dev.append(EZVIZSensor(data, option))
add_devices(dev, True)
-
+ data.regist()
+
class EZVIZSensor(Entity):
"""定义一个传感器的类,继承自HomeAssistant的Entity类."""
-
+
def __init__(self, data, option):
"""初始化."""
self._data = data
@@ -74,32 +78,32 @@ def __init__(self, data, option):
self._type = option
self._state = None
self._updatetime = None
-
+
@property
def name(self):
"""返回实体的名字."""
return self._object_id
-
+
@property
def registry_name(self):
"""返回实体的friendly_name属性."""
return self._friendly_name
-
+
@property
def state(self):
"""返回当前的状态."""
return self._state
-
+
@property
def icon(self):
"""返回icon属性."""
return self._icon
-
+
@property
def unit_of_measurement(self):
"""返回unit_of_measuremeng属性."""
return self._unit_of_measurement
-
+
@property
def device_state_attributes(self):
"""设置其它一些属性值."""
@@ -109,116 +113,372 @@ def device_state_attributes(self):
# 增加updatetime作为属性,表示获取的时间
ATTR_UPDATE_TIME: self._updatetime
}
-
+ return {}
+
def update(self):
# update只是从EZVIZData中获得数据,数据由EZVIZData维护。
self._updatetime = self._data.updatetime
if self._type == "privacyStatus":
self._state = self._data.privacyStatus
+ elif self._type == "sceneStatus":
+ self._state = self._data.sceneStatus
elif self._type == "alarmSoundMode":
- self._state = self._data.alarmSoundMode
- elif self._type == "AlarmStatus":
- self._state = self._data.AlarmStatus
+ self._state = self._data.alarmSoundMode
+ elif self._type == "pirStatus":
+ self._state = self._data.pirStatus
+ elif self._type == "defenceStatus":
+ self._state = self._data.defenceStatus
+ elif self._type == "onlineStatus":
+ self._state = self._data.onlineStatus
+ elif self._type == "motionStatus":
+ self._state = self._data.motionStatus
class EZVIZData(object):
"""摄像头的数据,存储在这个类中."""
def __init__(self, hass, deviceSerial,appKey,appSecret):
"""初始化函数."""
- self._params = {"accessToken": "",
- "deviceSerial": deviceSerial
- }
- self._apikey = {"appKey": appKey,
- "appSecret": appSecret
- }
+
+ self.hass = hass
+ self.deviceSerial = deviceSerial
+ self.apikey = {
+ "appKey": appKey,
+ "appSecret": appSecret
+ }
+ self.ENTITYID = "ezviz.home"
+ self.access_Token = ''
+
self._privacyStatus = None
- self._AlarmStatus = None
+ self._pirStatus = None
+ self._sceneStatus = None
self._alarmSoundMode = None
+ self._defenceStatus = None
+ self._onlineStatus = None
+ self._motionStatus = 0
self._updatetime = None
+ self.session = FuturesSession()
self.update(dt_util.now())
# 每隔TIME_BETWEEN_UPDATES,调用一次update()
track_time_interval(hass, self.update, TIME_BETWEEN_UPDATES)
-
+
@property
def privacyStatus(self):
"""隐私状态"""
return self._privacyStatus
-
+
@property
- def AlarmStatus(self):
- """报警状态"""
- return self._AlarmStatus
-
+ def defenceStatus(self):
+ """布防状态"""
+ return self._defenceStatus
+
+ @property
+ def onlineStatus(self):
+ """机器在线状态"""
+ return self._onlineStatus
+
+ @property
+ def motionStatus(self):
+ """是否有人体感应"""
+ return self._motionStatus
+
+ @property
+ def sceneStatus(self):
+ """遮蔽状态"""
+ return self._sceneStatus
+
+ @property
+ def pirStatus(self):
+ """红外状态"""
+ return self._pirStatus
+
@property
def alarmSoundMode (self):
"""提醒模式"""
return self._alarmSoundMode
-
+
@property
def updatetime(self):
"""更新时间."""
return self._updatetime
-
- def update(self, now):
+
+ def update(self, _):
"""从远程更新信息."""
- _LOGGER.info("Update the EZVIZ state...")
- statusCode = requests.post('https://open.ys7.com/api/lapp/device/list',data=self._params).json()["code"]
- if statusCode == "200":
- _LOGGER.info('TOKEN_SUCCESS')
- else:
- response = requests.post('https://open.ys7.com/api/lapp/token/get',data=self._apikey).json()
- #访问url
- if response["code"] == "200":
- _LOGGER.info('GET_TOKEN_SUCCESS')
- self._params["accessToken"] = response['data']['accessToken']
- else:
- _LOGGER.error("Error API return, code=%s, msg=%s",response['code'],response['msg'])
- return
+ _LOGGER.debug("Update the EZVIZ state...")
#POST获取数据
-
- result = requests.post('https://open.ys7.com/api/lapp/device/info',data=self._params).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
+ params = {}
+ status_url = "https://open.ys7.com/api/lapp/device/status/get"
+ result = self._post(status_url, params)
+ if result:
+ # 根据http返回的结果,更新数据
+ all_result = result['data']
+
+ if all_result['privacyStatus'] == 1:
+ self._privacyStatus = '启用隐私'
+ elif all_result['privacyStatus'] == 0:
+ self._privacyStatus = '关闭隐私'
+ else:
+ self._privacyStatus = '不支持'
- # 根据http返回的结果,更新数据
- all_result = result['data']
- # _LOGGER.error(all_result)
+ if all_result['pirStatus'] == 1:
+ self._pirStatus = '启用'
+ elif all_result['pirStatus'] == 0:
+ self._pirStatus = '关闭'
+ else:
+ self._pirStatus = '不支持'
+
+ if all_result['alarmSoundMode'] == 0:
+ self._alarmSoundMode = '短叫'
+ elif all_result['alarmSoundMode'] == 1:
+ self._alarmSoundMode = '长叫'
+ elif all_result['alarmSoundMode'] == 2:
+ self._alarmSoundMode = '静音'
+ else:
+ self._alarmSoundMode = '禁用或不支持'
- if all_result['defence'] == 1:
- self._AlarmStatus = '布防'
+ self.get_sceneStatus()
+ self.get_deviceInfo()
+ self.get_montionInfo()
+
+ self._updatetime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
+
+ def get_sceneStatus(self):
+ params = {}
+ scene_url = "https://open.ys7.com/api/lapp/device/scene/switch/status"
+ scene = self._post(scene_url, params)
+ if scene:
+ if scene['data']['enable'] == 1:
+ self._sceneStatus = '启用遮蔽'
+ else:
+ self._sceneStatus = '关闭遮蔽'
+
+ def get_deviceInfo(self):
+ #布防开关(活动状态检测开关)
+ url = "https://open.ys7.com/api/lapp/device/info"
+ params = {}
+ ret = self._post(url, params)
+ retdata = ret.get("data", {})
+ defence = retdata.get("defence", 0)
+ if defence == 0:
+ self._defenceStatus = "撤防"
else:
- self._AlarmStatus = '撤防'
-
- if all_result['alarmSoundMode'] == 0:
- self._alarmSoundMode = '短叫'
- elif all_result['alarmSoundMode'] == 1:
- self._alarmSoundMode = '长叫'
- elif all_result['alarmSoundMode'] == 2:
- self._alarmSoundMode = '静音'
+ self._defenceStatus = "布防"
+
+ #设备是否在线
+ online = retdata.get("status", 0)
+ if online == 0:
+ self._onlineStatus = "离线"
else:
- self._alarmSoundMode = '禁用或不支持'
-
- result = requests.post('https://open.ys7.com/api/lapp/device/scene/switch/status',data=self._params).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
+ self._onlineStatus = "在线"
+
+
+ def request_token(self) -> str:
+ #重新获取access_token
+ access_Token = ""
+ response_async = self.session.post('https://open.ys7.com/api/lapp/token/get',
+ data=self.apikey)
+ try:
+ response = response_async.result().json()
+ except RequestException as ex:
+ _LOGGER.error(ex)
+ return ""
- # 根据http返回的结果,更新数据
- all_result = result['data']
- if all_result['enable'] == 1:
- self._privacyStatus = '启用遮蔽'
+ #访问url
+ if response["code"] == "200":
+ _LOGGER.info('GET_TOKEN_SUCCESS')
+ access_Token = response['data']['accessToken']
+ attr = {'access_Token': access_Token}
+ self.hass.states.set(self.ENTITYID, 'OK', attributes=attr)
else:
- self._privacyStatus = '关闭遮蔽'
+ _LOGGER.error("Error API return, code=%s, msg=%s",response['code'],response['msg'])
+ return access_Token
-
- self._updatetime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
+ def Get_access_Token(self, isForce:bool=False):
+ if not self.access_Token:
+ entobj = self.hass.states.get(self.ENTITYID)
+ if entobj:
+ attr = entobj.attributes.copy()
+ self.access_Token = attr['access_Token']
+
+ if not self.access_Token:
+ self.access_Token = self.request_token()
+ return
+
+ if isForce:
+ self.access_Token = self.request_token()
+ _LOGGER.debug('TOKEN_SUCCESS')
+ return
+
+ def _post(self, url:str, data:dict) -> dict:
+ # 获取access_Token
+ self.Get_access_Token()
+ if not self.access_Token:
+ _LOGGER.error("Request Token Error")
+ return {}
+ default_data = {
+ "accessToken": self.access_Token,
+ "deviceSerial": self.deviceSerial
+ }
+ data.update(default_data)
+ trytimes = 2
+ ret = None
+ for _ in range(trytimes):
+ ret_async = self.session.post(url, data=data, timeout=5)
+ ret = ret_async.result()
+ if not ret.ok:
+ _LOGGER.warning("Request Error %s %s", url, str(data))
+ continue
+ break
+
+ if not ret or not ret.ok:
+ _LOGGER.error("Request Error %s %s", url, str(data))
+ return {}
+
+ result = ret.json()
+ if not result:
+ _LOGGER.error("Request Empty Error %s %s", url, str(data))
+ return {}
+
+ code = result.get("code", "0")
+ if code != "200":
+ _LOGGER.error("Error API return, code=%s, msg=%s, url=%s",
+ code,result['msg'], url)
+ return {}
+
+ return result
+
+
+ def enable_sence(self, _):
+ ctrl = {"enable": '1'}
+ url = 'https://open.ys7.com/api/lapp/device/scene/switch/set'
+ if self._post(url, ctrl):
+ # 更新传感器状态
+ self._sceneStatus = "启用遮蔽"
+ self.hass.states.set('sensor.ezviz_sceneStatus', self._sceneStatus)
+ _LOGGER.info("enable sence")
+
+ def disable_sence(self, _):
+ ctrl = {"enable": '0'}
+ url = 'https://open.ys7.com/api/lapp/device/scene/switch/set'
+ if self._post(url, ctrl):
+ self._sceneStatus = "关闭遮蔽"
+ self.hass.states.set('sensor.ezviz_sceneStatus', self._sceneStatus)
+ _LOGGER.info("disable sence")
+
+ def enable_defence(self, _):
+ #活动检测开关
+ ctrl = {"isDefence": '1'}
+ url = 'https://open.ys7.com/api/lapp/device/defence/set'
+ if self._post(url, ctrl):
+ # 更新传感器状态
+ self._defenceStatus = "布防"
+ self.hass.states.set('sensor.ezviz_defenceStatus', '布防')
+ _LOGGER.info("enable defence")
+
+ def disable_defence(self, _):
+ ctrl = {"isDefence": '0'}
+ url = 'https://open.ys7.com/api/lapp/device/defence/set'
+ if self._post(url, ctrl):
+ self._defenceStatus = "撤防"
+ self.hass.states.set('sensor.ezviz_defenceStatus', '撤防')
+ _LOGGER.info("disable defence")
+
+ def move(self, direc:int) -> str:
+ if not self.start(direc):
+ _LOGGER.error("move failed")
+ return 'FAIL'
+
+ # 等待0.2s后停止
+ time.sleep(0.2)
+
+ if not self.stop(direc):
+ return 'FAIL'
+ return 'OK'
+
+ def up(self, _):
+ self.move(0)
+
+ def down(self, _):
+ self.move(1)
+
+ def left(self, _):
+ self.move(2)
+
+ def right(self, _):
+ self.move(3)
+
+ def upleft(self, _):
+ self.move(4)
+
+ def downleft(self, _):
+ self.move(5)
+
+ def upright(self, _):
+ self.move(6)
+
+ def downright(self, _):
+ self.move(7)
+
+ def start(self, direc:int) -> bool:
+ ctrl = {
+ "channelNo": '1',
+ "direction": direc,
+ "speed": '1'
+ }
+ start_url = 'https://open.ys7.com/api/lapp/device/ptz/start'
+ return self._post(start_url, ctrl) != {}
+
+ def stop(self, call) -> bool:
+ ctrl = {
+ "channelNo": '1',
+ "direction": call,
+ }
+ url = 'https://open.ys7.com/api/lapp/device/ptz/stop'
+ return self._post(url, ctrl) != {}
+
+ #取间隔时间里的所有告警
+ def get_alarminfo(self) -> list[dict]:
+ startime = datetime.datetime.now() - TIME_BETWEEN_UPDATES
+ starttime_s = int(startime.timestamp() * 1000)
+ ctrl = {
+ "pageSize": 20,
+ "pageStart": 0,
+ "startTime": starttime_s,
+ "status": 2, #所有
+ }
+ url = "https://open.ys7.com/api/lapp/alarm/device/list"
+ ret = self._post(url, ctrl)
+ if not ret:
+ return []
+
+ return ret.get("data", [])
+
+ def get_montionInfo(self):
+ alarms = self.get_alarminfo()
+ for alarm in alarms:
+ _LOGGER.debug(alarm)
+ alarmType = alarm.get("alarmType", -1)
+ if alarmType in [10000, 15010]:
+ self._motionStatus = 1
+ return
+ self._motionStatus = 0
+ return
+
+ def regist(self):
+ # 注册服务
+ DOMAIN = "ezviz"
+ self.hass.services.register(DOMAIN, 'enable_sence', self.enable_sence)
+ self.hass.services.register(DOMAIN, 'disable_sence', self.disable_sence)
+ self.hass.services.register(DOMAIN, 'enable_defence', self.enable_defence)
+ self.hass.services.register(DOMAIN, 'disable_defence', self.disable_defence)
+ self.hass.services.register(DOMAIN, 'up', self.up)
+ self.hass.services.register(DOMAIN, 'down', self.down)
+ self.hass.services.register(DOMAIN, 'left', self.left)
+ self.hass.services.register(DOMAIN, 'right', self.right)
+ self.hass.services.register(DOMAIN, 'upright', self.upright)
+ self.hass.services.register(DOMAIN, 'downright', self.downright)
+ self.hass.services.register(DOMAIN, 'upleft', self.upleft)
+ self.hass.services.register(DOMAIN, 'downleft', self.downleft)
+ self.hass.services.register(DOMAIN, 'stop', self.stop)
+
+ return True
diff --git a/ezvizctrl/__init__.py b/ezvizctrl/__init__.py
deleted file mode 100755
index 1d78153..0000000
--- a/ezvizctrl/__init__.py
+++ /dev/null
@@ -1,297 +0,0 @@
-"""
-用途:以服务方式控制萤石摄像头
-版本:V0.1
-依赖:ezviz/sensor.py控件
-"""
-
-import json
-from urllib import request, parse
-import logging
-import requests
-from time import sleep
-
-import voluptuous as vol
-import homeassistant.helpers.config_validation as cv
-
-
-_LOGGER = logging.getLogger(__name__)
-
-DOMAIN = "ezvizctrl"
-ENTITYID = DOMAIN + ".home"
-
-# 预定义配置文件中的key值
-CONF_DEVICESERIAL = "deviceSerial"
-CONF_APPKEY = "appKey"
-CONF_APPSECRET = "appSecret"
-
-
-# 在python中,__name__代表模块名字
-_LOGGER = logging.getLogger(__name__)
-
-# 配置文件的样式
-CONFIG_SCHEMA = vol.Schema(
- {
- DOMAIN: vol.Schema(
- {
- vol.Required(CONF_DEVICESERIAL): cv.string,
- vol.Required(CONF_APPKEY): cv.string,
- vol.Required(CONF_APPSECRET): cv.string,
- }),
- },
- extra=vol.ALLOW_EXTRA)
-
-
-def setup(hass, config):
- """配置文件加载后,setup被系统调用."""
- conf = config[DOMAIN]
- deviceSerial = conf.get(CONF_DEVICESERIAL)
- appKey = conf.get(CONF_APPKEY)
- appSecret = conf.get(CONF_APPSECRET)
-
- access_Token = ''
- attr = {"access_Token": access_Token,}
-
- hass.states.set(ENTITYID, 'OK', attributes=attr)
-
- def Get_access_Token():
- # 记录info级别的日志
- _LOGGER.info("Update the EZVIZ state...")
- attr = hass.states.get(ENTITYID).attributes.copy()
- access_Token = attr['access_Token']
- params = {"accessToken": access_Token,
- "deviceSerial": deviceSerial
- }
- apikey = {"appKey": appKey,
- "appSecret": appSecret
- }
- # 检查access_token是否有效
- statusCode = requests.post('https://open.ys7.com/api/lapp/device/list',data=params).json()["code"]
- if statusCode == "200":
- _LOGGER.info('TOKEN_SUCCESS')
- else:
- #重新获取access_token
- response = requests.post('https://open.ys7.com/api/lapp/token/get',data=apikey).json()
- #访问url
- if response["code"] == "200":
- _LOGGER.info('GET_TOKEN_SUCCESS')
- access_Token = response['data']['accessToken']
- attr['access_Token'] = access_Token
- hass.states.set(ENTITYID, 'OK', attributes=attr)
- else:
- _LOGGER.error("Error API return, code=%s, msg=%s",response['code'],response['msg'])
- return
- return access_Token
-
- def Enable_privacy(call):
- # 获取access_Token
- access_Token = Get_access_Token()
- if access_Token is None:
- _LOGGER.error("Request Token Error")
- return
- ctrl = {"accessToken": access_Token,
- "deviceSerial": deviceSerial,
- "enable": '1'
- }
- result = requests.post('https://open.ys7.com/api/lapp/device/scene/switch/set',data=ctrl).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
- # 更新传感器状态
- hass.states.set('sensor.ezviz_privacystatus', '启用遮蔽')
-
- def Disable_privacy(call):
- # 获取access_Token
- access_Token = Get_access_Token()
- if access_Token is None:
- _LOGGER.error("Request Token Error")
- return
- ctrl = {"accessToken": access_Token,
- "deviceSerial": deviceSerial,
- "enable": '0'
- }
- result = requests.post('https://open.ys7.com/api/lapp/device/scene/switch/set',data=ctrl).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
- hass.states.set('sensor.ezviz_privacystatus', '关闭遮蔽')
-
- def Enable_alarm(call):
- # 获取access_Token
- access_Token = Get_access_Token()
- if access_Token is None:
- _LOGGER.error("Request Token Error")
- return
- ctrl = {"accessToken": access_Token,
- "deviceSerial": deviceSerial,
- "isDefence": '1'
- }
- result = requests.post('https://open.ys7.com/api/lapp/device/defence/set',data=ctrl).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
- # 更新传感器状态
- hass.states.set('sensor.ezviz_alarmstatus', '布防')
-
- def Disable_alarm(call):
- # 获取access_Token
- access_Token = Get_access_Token()
- if access_Token is None:
- _LOGGER.error("Request Token Error")
- return
- ctrl = {"accessToken": access_Token,
- "deviceSerial": deviceSerial,
- "isDefence": '0'
- }
- result = requests.post('https://open.ys7.com/api/lapp/device/defence/set',data=ctrl).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
- # 更新传感器状态
- hass.states.set('sensor.ezviz_alarmstatus', '撤防')
-
- def move(direc):
- # 获取access_Token
- access_Token = Get_access_Token()
- if access_Token is None:
- _LOGGER.error("Request Token Error")
- return
- ctrl = {"accessToken": access_Token,
- "deviceSerial": deviceSerial,
- "channelNo": '1',
- "direction": direc,
- "speed": '1'
- }
- result = requests.post('https://open.ys7.com/api/lapp/device/ptz/start',data=ctrl).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
- # 等待0.2s后停止
- sleep(0.2)
- ctrl = {"accessToken": access_Token,
- "deviceSerial": deviceSerial,
- "channelNo": '1',
- "direction": direc
- }
- result = requests.post('https://open.ys7.com/api/lapp/device/ptz/stop',data=ctrl).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- ##防止因为意外再次执行停止
- result = requests.post('https://open.ys7.com/api/lapp/device/ptz/stop',data=ctrl).json()
- if result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
- return 'OK'
-
- def up(call):
- result = move(0)
- if result is None:
- _LOGGER.error("move failed")
- return
-
- def down(call):
- result = move(1)
- if result is None:
- _LOGGER.error("move failed")
- return
-
- def left(call):
- result = move(2)
- if result is None:
- _LOGGER.error("move failed")
- return
-
- def right(call):
- result = move(3)
- if result is None:
- _LOGGER.error("move failed")
- return
-
- def upleft(call):
- result = move(4)
- if result is None:
- _LOGGER.error("move failed")
- return
-
- def downleft(call):
- result = move(5)
- if result is None:
- _LOGGER.error("move failed")
- return
-
- def upright(call):
- result = move(6)
- if result is None:
- _LOGGER.error("move failed")
- return
-
- def downright(call):
- result = move(7)
- if result is None:
- _LOGGER.error("move failed")
- return
-
- def stop(call):
- # 获取access_Token
- access_Token = Get_access_Token()
- if access_Token is None:
- _LOGGER.error("Request Token Error")
- return
- ctrl = {"accessToken": access_Token,
- "deviceSerial": deviceSerial,
- "channelNo": '1'
- }
- result = requests.post('https://open.ys7.com/api/lapp/device/ptz/stop',data=ctrl).json()
- if result is None:
- _LOGGER.error("Request api Error")
- return
- elif result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- ##防止因为意外再次执行停止
- result = requests.post('https://open.ys7.com/api/lapp/device/ptz/stop',data=ctrl).json()
- if result["code"] != "200":
- _LOGGER.error("Error API return, code=%s, msg=%s",
- result['code'],result['msg'])
- return
-
- # 注册服务
- hass.services.register(DOMAIN, 'Enable_privacy', Enable_privacy)
- hass.services.register(DOMAIN, 'Disable_privacy', Disable_privacy)
- hass.services.register(DOMAIN, 'Enable_alarm', Enable_alarm)
- hass.services.register(DOMAIN, 'Disable_alarm', Disable_alarm)
- hass.services.register(DOMAIN, 'up', up)
- hass.services.register(DOMAIN, 'down', down)
- hass.services.register(DOMAIN, 'left', left)
- hass.services.register(DOMAIN, 'right', right)
- hass.services.register(DOMAIN, 'upright', upright)
- hass.services.register(DOMAIN, 'downright', downright)
- hass.services.register(DOMAIN, 'upleft', upleft)
- hass.services.register(DOMAIN, 'downleft', downleft)
- hass.services.register(DOMAIN, 'stop', stop)
-
- return True