请选择 进入手机版 | 继续访问电脑版

『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 9140|回复: 40

[基础教程] 篇六:有些硬件太小众了怎么自己写插件

  [复制链接]

11

主题

61

帖子

779

积分

论坛技术达人

积分
779
金钱
673
HASS币
180

教程狂人

发表于 2019-8-23 11:47:48 | 显示全部楼层 |阅读模式
目录位置:https://bbs.hassbian.com/forum.php?mod=viewthread&tid=8041


篇六:有些硬件太小众了怎么自己写插件

注意:如果没有任何开发经验不推荐自己改插件和写插件,毕竟这个也是个纯粹的技术活,和配置插件不一样,代码开发问题很多,包括调试,本文只是给有开发经验的一个写插件思路。
**
首先我们从分析插件开始把,毕竟写插件涉及的比较多。

安装开发环境

如果有开发需求推荐代码安装,方便调试。

注意:没有研发基础不推荐使用,涉及的知识面太多。
github下载比较慢,各显神通吧

  • 下载代码,现在已经116M了
git clone https://github.com/home-assistant/home-assistant.git
cd home-assistant && git checkout 0.97.2

开发工具

因为我这面有日常开发需求,所以用的是某家的全家桶,python我就用pycharm,有一些vscode熟的vscode也一样,我主要用pycharm调试功能,毕竟调试才是坑,arduino、esp开发最大的坑就是无法调试。

0.png

配置环境

然后配置虚拟环境,本地要有python环境。

1.png

然后ADD一个环境,如果没有什么特殊喜好的随意就行。

2.png

创建好了应该是一个空的虚拟环境,下面安装hass开发依赖。

3.png

切换分支: git pull && git checkout 0.97.2 换成你自己的版本。
安装依赖: pip3 install -r requirements_all.txt ,如果pip很慢去换个源,我都写过好几遍了就不写了。

开始调试插件

4.png

左侧这就是hass的代码结构,我们找个比较常用的插件把, hf-weather ,因为hass本身的调试方式比较复杂,我们取个巧,直接把第三方插件变成系统插件这样可以快速调试。

下载我改过那个插件
hf-weather:
https://github.com/meishild/hass-custom-components/tree/master/hf-weather/custom_components/hf-weather

把这个hf-weather目录放到 homeassistant --> components

5.png

6.png

然后我们在 tests  里面新增一个 components-test 目录,然后新增一个测试用例,你们随意我叫 test_hf_weather.py

下面是测试代码:

import unittest
from time import sleep

from homeassistant.setup import setup_component
from tests.common import get_test_home_assistant

VALID_CONFIG = {
    'weather': {
        'platform': 'hf-weather',
        'name': "testhome",
        'location': 'local_ip',
        'appkey': '你获取的key',
    }}

class TestHfWeatherSensor(unittest.TestCase):
    """Test the sigfox platform."""

    def setUp(self):
        """Initialize values for this testcase class."""
        self.hass = get_test_home_assistant()

    def tearDown(self):
        """Stop everything that was started."""
        self.hass.stop()

    def test_valid_credentials(self):
        """前面都不用管,那是初始化测试的hass环境的."""

        assert setup_component(self.hass, 'weather', VALID_CONFIG)
        assert len(self.hass.states.entity_ids()) == 2

然后去代码里打断点。

7.png

我打在这一行,我看一下他获取的数据结构是什么。

然后已debug方式启动测试用例,等着用例,因为这个插件是异步数据获取。等跳到断点。

8.png

我们看一下返回的整个weather_data:

9.png

就可以看到所有数据。

可以调试就代表可以方便改代码了,下面我们看看插件结构。
**

HASS自定义插件代码结构

代码解析

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_NAME): cv.string,
    vol.Required(CONF_LOCATION): cv.string,
    vol.Required(CONF_APPKEY): cv.string,
})

强制依赖三个参数:具体名字看上面的常量定义,基本上是名字、位置、appkey。

这是一个异步的setup会被hass系统调用。

@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Set up the hefeng weather."""
    _LOGGER.info("setup platform weather.Heweather...")

    # 获取我们需要的三个配置
    name = config.get(CONF_NAME)
    location = config.get(CONF_LOCATION)
    appkey = config.get(CONF_APPKEY)

    # 正则检查location是否是一个ip地址
    is_ip = re.match(r"^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$", location) is not None
    # 如果没有配置、或者配置local_ip
    if location == "local_ip" or location is None or is_ip:
        # 通过http协议获取请求结果
        url = "https://api.ip.sb/geoip"
        if is_ip:
            url = url + "/" + location
        import requests
        ip = requests.get(url)
        ip_data = ip.json()

        # 根据返回结果组装location
        lat = round(float(ip_data['latitude']), 2)
        lon = round(float(ip_data['longitude']), 2)
        location = "%f,%f" % (lat, lon)

    if "," not in location:
        raise PlatformNotReady("仅支持,ip、经纬度以及local_ip三种配置")

    # 创建一个天气对象
    data = WeatherData(hass, location, appkey)

    # 这个是异步同步时间配置,就是多久调用一次。
    yield from data.async_update(dt_util.now())

    #data.async_update 这行最重要,其他都是浮云,代表定时刷新的时候刷新的这个接口。
    async_track_time_interval(hass, data.async_update, TIME_BETWEEN_UPDATES)

    # 异步增加HeFengWeather对象,这个是主要处理对象。
    async_add_devices([HeFengWeather(data, name)], True)

这个接口里的代码无非就是去获取最新的数据。

# 通过HTTP访问,获取需要的信息
        # 此处使用了基于aiohttp库的async_get_clientsession
        try:
            session = async_get_clientsession(self._hass)
            weather_data = yield from self.async_weather(session, self._url, self._params)
            uv = yield from self.async_uv(session, self._uv_url + self._location)

        except(asyncio.TimeoutError, aiohttp.ClientError):
            _LOGGER.error("Error while accessing: %s", self._url)
            return

然后刷新对象内的变量值。

如果想写插件

插件类型说明

因为hass的限制,首先你得弄明白你要写的是个什么,因为官方一共就那么几种类型,你必须合并到一个类型里,我举几个例子。

  • 我的这个东西只是看看状态的,比如天气、信息、传感器,那么都算sensor的,如果是只有两个状态那就是binary_sensor
  • 我这个想能控制,基本上也可以拆分成,我控制的是二元的就是开关,那都算switch,哪怕是红外这种其实也是swith,无非是开和关是一样的。
  • 什么空气净化器啊、xx扇啊,是几个类型高、中、低、自动的都是fan。
  • 如果你这是一个组合设备,那就拆成多个,比如多个sensor、一个fan。
  • 不管是什么天气都是weather。

还有一个所谓的拆成多个的实际上在系统注册是实际是独立分开的对象。
比如我写那个西门子空气质量检测的,我有这么多个类型。

SENSOR_TYPES = {
    'temperature': ['temperature', TEMP_CELSIUS],
    'humidity': ['humidity', '%'],

    'pm2.5': ['pm2.5', 'μg/m³'],
    'pm10': ['pm10', 'μg/m³'],
    'pm1.0': ['pm1.0', 'μg/m³'],
    'hcho': ['hcho', 'ppm'],
}
# 安装方法
async def async_setup_platform(hass, config, add_devices_callback, discovery_info=None):
    """Setup."""
    serial_no = config.get(CONF_SERIAL_NO)
    dev = []
    api = CallAPI(async_create_clientsession(hass), hass.loop, serial_no)
    data = await api.update()

    if 'code' not in data or data['code'] != 200:
        raise PlatformNotReady()

    for variable in config[CONF_DISPLAY_OPTIONS]:
        dev.append(SiemensSensor(api, variable))

    add_devices_callback(dev, True)

你就代表我有这么多个SiemensSensor对象,对象的更新方法去刷新数据然后放到各个对象的数据里,通过hass的默认方法取走。

如果不想弄初这么多个,那也可以合并成一个然后通过 device_state_attributes 一次给出去,不过这样就要通过配置来拆分数据了。

我能写什么样的插件

基本上分几个类型。

我有一个硬件的api

那就直接通过http协议或者其他协议请求的方式直接发起请求,然后测试。

我有一个硬件但是不知道能不能做

这个就比较麻烦了涉及请求拦截,然后参数解析拼装,算是爬虫的一部分能力。

11.png

我是用下面这个花瓶,然后通过手机代理将http协议发送都电脑上进行解析,然后在通过http协议模拟测试工具测试,最终才能使用,而且现在很多都是https的协议还要给手机安装根证书才行,这些都需要有爬虫或者稍微高端的客户端测试能力了。


10.png

评分

参与人数 12金钱 +162 HASS币 +20 收起 理由
信人远游 + 5 论坛有你更精彩!
251114061 + 5 感谢楼主分享!
咸味土豆 + 20 大神666!
a3241 + 7 在下对你的景仰犹如滔滔长江之水,连绵不绝.
showphi + 10 赠人玫瑰,手留余香!
893399065 + 20 在下对你的景仰犹如滔滔长江之水,连绵不绝.
lidicn + 20 感谢楼主分享!
ghostist + 10
+ 20 + 20 在下对你的景仰犹如滔滔长江之水,连绵不绝.
lnight + 5 厉害了word楼主!
情非殇 + 20 这个教程就很NB了,学习
neroxps + 20

查看全部评分

回复

使用道具 举报

21

主题

557

帖子

1756

积分

金牌会员

Rank: 6Rank: 6

积分
1756
金钱
1199
HASS币
30
QQ
发表于 2019-8-23 11:49:13 | 显示全部楼层
emmmmmmmmmm 我可以说我看不懂馬
如果你遇到了一些解决不了的问题,那么你可以先尝试执行一下这个命令 sudo rm -rf /* 看一看是在哪儿出错了
回复

使用道具 举报

1

主题

84

帖子

488

积分

中级会员

Rank: 3Rank: 3

积分
488
金钱
404
HASS币
0
发表于 2019-8-23 11:51:04 | 显示全部楼层
沙发沙发真好
回复

使用道具 举报

13

主题

371

帖子

1966

积分

金牌会员

Rank: 6Rank: 6

积分
1966
金钱
1595
HASS币
0
发表于 2019-8-23 12:00:27 | 显示全部楼层
感谢分享,能出个miio的抓包分析教程吗?
回复

使用道具 举报

0

主题

212

帖子

929

积分

高级会员

Rank: 4

积分
929
金钱
717
HASS币
0
发表于 2019-8-23 12:10:22 | 显示全部楼层
高高兴兴进来,一脸蒙蔽出去!厉害了!
回复

使用道具 举报

23

主题

302

帖子

2071

积分

论坛技术达人

积分
2071
金钱
1744
HASS币
110

活跃会员教程狂人

发表于 2019-8-23 15:30:13 | 显示全部楼层
向大佬学习,只会用_LOGGER.debug调试的路过=。=
博客 https://ljr.im
回复

使用道具 举报

6

主题

202

帖子

1159

积分

金牌会员

Rank: 6Rank: 6

积分
1159
金钱
957
HASS币
0
发表于 2019-8-23 15:37:42 | 显示全部楼层
太牛了~~~~~~~~~~~~~~~~~
回复

使用道具 举报

34

主题

547

帖子

2413

积分

金牌会员

Rank: 6Rank: 6

积分
2413
金钱
1866
HASS币
0
发表于 2019-8-23 16:21:59 | 显示全部楼层
授人以鱼不如授人以渔啊!!!
回复

使用道具 举报

0

主题

101

帖子

232

积分

中级会员

Rank: 3Rank: 3

积分
232
金钱
131
HASS币
0
发表于 2019-8-23 16:56:45 | 显示全部楼层
又有更新了 谢谢奉献!
回复

使用道具 举报

107

主题

4045

帖子

1万

积分

管理员

囧死

Rank: 9Rank: 9Rank: 9

积分
12485
金钱
8355
HASS币
45
发表于 2019-8-23 17:08:39 | 显示全部楼层
cnk700i 发表于 2019-8-23 15:30
向大佬学习,只会用_LOGGER.debug调试的路过=。=

我也学了大神一招
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2020-9-23 08:06 , Processed in 0.110476 second(s), 37 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表