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

 找回密码
 立即注册

[经验分享] 修改大佬xiao_miot,使儿童手表定位不在偏移

[复制链接]

7

主题

1075

帖子

3373

积分

论坛元老

Rank: 8Rank: 8

积分
3373
金钱
2298
HASS币
0
 楼主| 发表于 2023-3-28 11:54:44 | 显示全部楼层
ysst4 发表于 2023-3-28 09:40
原来如此,替换后,重启HA,米兔5C的地址终于的改回来啦。

方便多了哈,就是加了一个坐标系转换。
回复

使用道具 举报

6

主题

267

帖子

2375

积分

论坛技术达人

积分
2375
金钱
2088
HASS币
90
发表于 2023-3-28 13:12:31 | 显示全部楼层
感谢分享!为了避免大家更新插件后转换代码失效,我已经在插件添加了转换坐标的代码,升级到master分支或者等待下个版本(v0.7.8)发布即可。
https://github.com/al-one/hass-x ... ecomment-1486222887

评分

参与人数 1金钱 +12 收起 理由
咸味土豆 + 12 膜拜大神!

查看全部评分

小米MIoT插件:miot-spec.com
回复

使用道具 举报

7

主题

1075

帖子

3373

积分

论坛元老

Rank: 8Rank: 8

积分
3373
金钱
2298
HASS币
0
 楼主| 发表于 2023-3-28 13:29:50 | 显示全部楼层
anlong 发表于 2023-3-28 13:12
感谢分享!为了避免大家更新插件后转换代码失效,我已经在插件添加了转换坐标的代码,升级到master分支或者 ...

大佬出现了,感谢大佬点名。
回复

使用道具 举报

11

主题

266

帖子

2574

积分

金牌会员

Rank: 6Rank: 6

积分
2574
金钱
2298
HASS币
50
发表于 2023-3-28 14:18:27 来自手机 | 显示全部楼层
安龙大佬当晚回复我,转天就合并了。感谢本帖作者、插件作者的贡献。
回复

使用道具 举报

7

主题

1075

帖子

3373

积分

论坛元老

Rank: 8Rank: 8

积分
3373
金钱
2298
HASS币
0
 楼主| 发表于 2023-3-28 14:52:25 | 显示全部楼层
秋雨轩 发表于 2023-3-28 14:18
安龙大佬当晚回复我,转天就合并了。感谢本帖作者、插件作者的贡献。

感谢anlong大佬编写了这么优秀的插件。
回复

使用道具 举报

0

主题

39

帖子

350

积分

中级会员

Rank: 3Rank: 3

积分
350
金钱
311
HASS币
0
发表于 2023-4-3 11:01:01 | 显示全部楼层
anlong 发表于 2023-3-28 13:12
感谢分享!为了避免大家更新插件后转换代码失效,我已经在插件添加了转换坐标的代码,升级到master分支或者 ...

谢谢您的插件。
但我已经升级到了最新版,可重启后发现转换仍未生效(我也是米兔6X),请问这可能是什么原因呢?
盼复,谢谢!
回复

使用道具 举报

0

主题

74

帖子

1029

积分

金牌会员

Rank: 6Rank: 6

积分
1029
金钱
955
HASS币
0
发表于 2023-4-3 18:33:38 | 显示全部楼层
感谢老王同志结束我儿子每天在山上的生活,也感谢anlong大神合并到插件后免去每次更新替换的麻烦,论坛有你们更精彩!
回复

使用道具 举报

0

主题

74

帖子

1029

积分

金牌会员

Rank: 6Rank: 6

积分
1029
金钱
955
HASS币
0
发表于 2023-4-3 18:37:24 | 显示全部楼层
fuhao3503 发表于 2023-4-3 11:01
谢谢您的插件。
但我已经升级到了最新版,可重启后发现转换仍未生效(我也是米兔6X),请问这可能是什么 ...

现版本是0.7.7,下个版本才是0.7.8,才有坐标转换功能。
回复

使用道具 举报

0

主题

74

帖子

1029

积分

金牌会员

Rank: 6Rank: 6

积分
1029
金钱
955
HASS币
0
发表于 2023-4-3 18:42:55 | 显示全部楼层
因为5X和6X使用的坐标系不同,借宝地分享下5X的转换
"""Support for Xiaomi device tracker."""
import logging
import time,math
from datetime import timedelta
x_pi = 3.14159265358979324 * 3000.0 / 180.0
pi = 3.1415926535897932384626
a = 6378245.0
ee = 0.00669342162296594323

from homeassistant.const import *  # noqa: F401
from homeassistant.components.device_tracker import (
    DOMAIN as ENTITY_DOMAIN,
)
from homeassistant.components.device_tracker.const import SOURCE_TYPE_GPS
from homeassistant.components.device_tracker.config_entry import TrackerEntity

from . import (
    DOMAIN,
    CONF_MODEL,
    XIAOMI_CONFIG_SCHEMA as PLATFORM_SCHEMA,  # noqa: F401
    MiotEntity,
    async_setup_config_entry,
    bind_services_to_entries,
)
from .core.miot_spec import (
    MiotSpec,
    MiotService,
)

_LOGGER = logging.getLogger(__name__)
DATA_KEY = f'{ENTITY_DOMAIN}.{DOMAIN}'
SCAN_INTERVAL = timedelta(seconds=60)

SERVICE_TO_METHOD = {}

#BD09转为WGS84 
def out_of_china(lng, lat):
    return not (lng > 73.66 and lng < 135.05 and lat > 3.86 and lat < 53.55)
 
def _lat(lng, lat):
    ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \
          0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(lng))
    ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
            math.sin(2.0 * lng * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lat * pi) + 40.0 *
            math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
    ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 *
            math.sin(lat * pi / 30.0)) * 2.0 / 3.0
    return ret
 
 
def _lng(lng, lat):
    ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \
          0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(lng))
    ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 *
            math.sin(2.0 * lng * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lng * pi) + 40.0 *
            math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
    ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 *
            math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
    return ret
 
def bd09_to_gcj02(bd_lon, bd_lat):
    x = bd_lon - 0.0065
    y = bd_lat - 0.006
    z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
    theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
    gg_lng = z * math.cos(theta)
    gg_lat = z * math.sin(theta)
    return [gg_lng, gg_lat]
 
def gcj02_to_wgs84(lng, lat):
    if out_of_china(lng, lat):
        return [lng, lat]
    dlat = _lat(lng - 105.0, lat - 35.0)
    dlng = _lng(lng - 105.0, lat - 35.0)
    radlat = lat / 180.0 * pi
    magic = math.sin(radlat)
    magic = 1 - ee * magic * magic
    sqrtmagic = math.sqrt(magic)
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
    dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
    mglat = lat + dlat
    mglng = lng + dlng
    return [lng * 2 - mglng, lat * 2 - mglat]
 
def bd09_to_wgs84(bd_lon, bd_lat):
    lon, lat = bd09_to_gcj02(bd_lon, bd_lat)
    return gcj02_to_wgs84(lon, lat)


async def async_setup_entry(hass, config_entry, async_add_entities):
    await async_setup_config_entry(hass, config_entry, async_setup_platform, async_add_entities, ENTITY_DOMAIN)


async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
    hass.data.setdefault(DATA_KEY, {})
    hass.data[DOMAIN]['add_entities'][ENTITY_DOMAIN] = async_add_entities
    config['hass'] = hass
    model = str(config.get(CONF_MODEL) or '')
    spec = hass.data[DOMAIN]['miot_specs'].get(model)
    entities = []
    if isinstance(spec, MiotSpec):
        for srv in spec.get_services('watch', 'rearview_mirror', 'head_up_display'):
            if 'xiaoxun.watch.' in model:
                entities.append(XiaoxunWatchTrackerEntity(config, srv))
            elif srv.get_property('latitude', 'longitude'):
                entities.append(MiotTrackerEntity(config, srv))
    if not entities and ('xiaoxun.watch.' in model or 'xiaoxun.tracker.' in model):
        # xiaoxun.watch.sw763
        # xiaoxun.tracker.v1
        entities.append(XiaoxunWatchTrackerEntity(config))
    for entity in entities:
        hass.data[DOMAIN]['entities'][entity.unique_id] = entity
    async_add_entities(entities, update_before_add=True)
    bind_services_to_entries(hass, SERVICE_TO_METHOD)


class MiotTrackerEntity(MiotEntity, TrackerEntity):
    _attr_latitude = None
    _attr_longitude = None
    _attr_location_name = None
    _attr_location_accuracy = 0
    _disable_location_name = False

    def __init__(self, config, miot_service: MiotService = None):
        super().__init__(miot_service, config=config, logger=_LOGGER)

    async def async_added_to_hass(self):
        await super().async_added_to_hass()
        self._disable_location_name = self.custom_config_bool('disable_location_name')

    async def async_update(self):
        await super().async_update()
        if not self._available or not self._miot_service:
            return

        if prop := self._miot_service.get_property('latitude'):
            self._attr_latitude = prop.from_dict(self._state_attrs)
        if prop := self._miot_service.get_property('longitude'):
            self._attr_longitude = prop.from_dict(self._state_attrs)
        if prop := self._miot_service.get_property('current_address'):
            self._attr_location_name = prop.from_dict(self._state_attrs)

        for p in self._miot_service.get_properties('driving_status'):
            self._update_sub_entities(p, None, 'binary_sensor')

    @property
    def should_poll(self):
        """No polling for entities that have location pushed."""
        return True

    @property
    def source_type(self):
        """Return the source type, eg gps or router, of the device."""
        return SOURCE_TYPE_GPS

    @property
    def latitude(self):
        """Return latitude value of the device."""
        return self._attr_latitude

    @property
    def longitude(self):
        """Return longitude value of the device."""
        return self._attr_longitude

    @property
    def location_name(self):
        """Return a location name for the current location of the device."""
        if self._disable_location_name:
            return None
        return self._attr_location_name

    @property
    def location_accuracy(self):
        """Return the location accuracy of the device.
        Value in meters.
        """
        return self._attr_location_accuracy

    @property
    def battery_level(self):
        """Return the battery level of the device."""
        if not self._miot_service:
            return None
        sls = [self._miot_service, *self._miot_service.spec.get_services('battery')]
        for srv in sls:
            prop = srv.get_property('battery_level')
            if prop:
                return prop.from_dict(self._state_attrs)
        return None


class XiaoxunWatchTrackerEntity(MiotTrackerEntity):
    def __init__(self, config, miot_service: MiotService = None, miot_spec: MiotSpec = None):
        self._miot_spec = miot_spec
        super().__init__(config=config, miot_service=miot_service)

    @property
    def device_eid(self):
        did = f'{self.miot_did}'
        return did.replace('xiaoxun.', '')

    async def async_update(self):
        await super().async_update()
        await self.update_location()

    async def update_location(self):
        did = f'{self.miot_did}'
        mic = self.xiaomi_cloud
        if not did or not mic:
            return
        pms = {
            'app_id': '10025',
            'dids': [did],
            'params': {
                'CID': 50031,
                'model': self._model,
                'SN': int(time.time() / 1000),
                'PL': {
                    'Size': 1,
                    'Key': '78999898989898998',
                    'EID': self.device_eid,
                },
            },
        }
        rdt = await mic.async_request_api('third/api', pms) or {}
        loc = {}
        for v in (rdt.get('result') or {}).get('PL', {}).get('List', {}).values():
            loc = v.get('result', {})
            break
        if not loc:
            self.logger.warning('%s: Got xiaoxun watch location faild: %s', self.name_model, rdt)
            return
        self.logger.debug('%s: Got xiaoxun watch location: %s', self.name_model, rdt)
        gps = f"{loc.get('location', '')},".split(',')
        gps=bd09_to_wgs84(float(gps[0]),float(gps[1]))  #修改为wgs84坐标
        self._attr_latitude = float(gps[1])
        self._attr_longitude = float(gps[0])
        self._attr_location_name = loc.get('desc')
        self._attr_location_accuracy = int(loc.get('radius') or 0)
        tim = loc.get('timestamp', '')
        self.update_attrs({
            'timestamp': f'{tim[0:4]}-{tim[4:6]}-{tim[6:8]} {tim[8:10]}:{tim[10:12]}:{tim[12:14]}',
        })

评分

参与人数 1金钱 +12 收起 理由
咸味土豆 + 12 大神666!

查看全部评分

回复

使用道具 举报

7

主题

1075

帖子

3373

积分

论坛元老

Rank: 8Rank: 8

积分
3373
金钱
2298
HASS币
0
 楼主| 发表于 2023-4-3 22:53:33 | 显示全部楼层
Xi11 发表于 2023-4-3 18:42
因为5X和6X使用的坐标系不同,借宝地分享下5X的转换

along大佬好像新版本可以自选坐标系了
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-5-6 04:50 , Processed in 0.114139 second(s), 32 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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