找回密码
 立即注册

微信扫码登录

搜索
查看: 356|回复: 2

[Zemismart] 智能人体存在传感器ZPS-Z1免费测评

[复制链接]

10

主题

359

回帖

4938

积分

论坛元老

积分
4938
金钱
4569
HASS币
0
发表于 2026-6-17 22:49:56 | 显示全部楼层 |阅读模式
感谢论坛提供的测评机会,今天收到快递,直接开始

一、包装&&外观
拆开快递盒,小小的一个盒子
IMG_7614.jpeg
继续拆,直接把传感器拿出来
IMG_7615.jpeg
主体旋转可以打开,拉出电池的绝缘纸,就可以直接用了
IMG_7616.jpeg
很小巧,底座是双面胶可以贴到需要安装的地方。
二、拆机
这是我的习惯,自己买的智能家居产品也都会拆开看看内部,测评的当然也不例外
IMG_7619.jpeg
IMG_7620.jpeg
下面就是用两根排针和电池板相连的,就不继续拆了,看了下背部除了一个涂鸦模块,没有其他元件了。
三、接入网关
1)涂鸦网关
我目前主要使用的是涂鸦 matter 网关,先把传感器接入涂鸦网关看看效果
长按电池旁边的按钮,闪红灯后即可配对
IMG_7617.jpeg
接入后看了下 有人体感应和光照,可设置的也还挺多
IMG_7618.jpeg IMG_7631.jpeg IMG_7630.jpeg IMG_7629.jpeg IMG_7628.jpeg IMG_7627.jpeg IMG_7623.jpeg
最让我感兴趣的是这个自动学习,大概看了下,是可以根据触发有人状态时的能量,可以人为把误触发的错误记录删除,目前只装了使用一下午,暂时不知道是否准确。
d3ed4bb4c66e75687c80fac888dc2f4e.jpg
通过 matter 接入homekit 和 homeassistant 的情况
iShot_2026-06-17_11.34.22.png
iShot_2026-06-17_11.36.10.png iShot_2026-06-17_11.36.16.png
2)zigbee2mqtt 网关接入
z2m 暂时不支持这个传感器,我在github 上搜了一下,有人提交了,但是还没通过,不确定啥时候可以支持,但是已经有人给出使用方法了,https://github.com/Koenkk/zigbee-herdsman-converters/issues/11791
简单就是 z2mweb 中,打开 z2mweb-设置-开发控制台-外部转换器
image.png
创建新转换器
image.png 名称随意.js 后缀即可
把下面代码复制到代码输入框中
'use strict';

// ─── Constants ────────────────────────────────────────────────────────────────

const TUYA_CLUSTER = 'manuSpecificTuya';

const DP = {
    PRESENCE_STATE:     1,
    DETECTION_RANGE:    2,
    ILLUMINANCE:        101,
    ENERGY_VALUE:       102,
    AI_SELF_LEARNING:   103,
    HEARTBEAT_ENABLE:   104,
    HEART:              105,
    SENSITIVITY_PRESET: 112,
    ZONE_MAP:           117,
    NO_PERSON_TIME:     119,
    INDICATOR:          123,
    ENERGY_THRESHOLD:   124,
};

const DT = { RAW: 0x00, BOOL: 0x01, VALUE: 0x02, ENUM: 0x04 };

const ZONE_COUNT = 10;

// ─── Scaling helpers (0–100 ↔ 0–255) ─────────────────────────────────────────

function toApp(raw)  { return Math.round((raw  / 255) * 100); }
function toRaw(app)  { return Math.round((app  / 100) * 255); }

// ─── Keep-alive (DP104) ──────────────────────────────────────────────────────

const keepAliveTimers = {};

function startKeepAlive(device, endpoint) {
    stopKeepAlive(device.ieeeAddr);
    keepAliveTimers[device.ieeeAddr] = setInterval(async () => {
        try {
            await endpoint.command(
                TUYA_CLUSTER, 'dataRequest',
                { seq: Math.round(Math.random() * 0xFFFF), dpValues: [{ dp: DP.HEARTBEAT_ENABLE, datatype: DT.BOOL, data: [1] }] },
                { disableDefaultResponse: true },
            );
        } catch (_) { /* transient error — will retry in 5 s */ }
    }, 5000);
}

function stopKeepAlive(ieeeAddr) {
    if (keepAliveTimers[ieeeAddr]) {
        clearInterval(keepAliveTimers[ieeeAddr]);
        delete keepAliveTimers[ieeeAddr];
    }
}

// ─── Helpers ──────────────────────────────────────────────────────────────────

async function sendDP(endpoint, dp, datatype, data) {
    await endpoint.command(
        TUYA_CLUSTER, 'dataRequest',
        { seq: Math.round(Math.random() * 0xFFFF), dpValues: [{ dp, datatype, data }] },
        { disableDefaultResponse: true },
    );
}

/** Read current cached zone active states from Z2M state, falling back to true (active). */
function currentZoneArray(meta) {
    const state = meta.state ?? {};
    return Array.from({ length: ZONE_COUNT }, (_, i) => {
        const v = state[`zone_${i + 1}_active`];
        return (v === false) ? false : true;
    });
}

/** Encode array of zone active booleans → 10-byte Buffer. 1=active, 0=blocked. */
function encodeZoneMap(zones) {
    const buf = Buffer.alloc(ZONE_COUNT, 1);
    zones.forEach((active, i) => { buf[i] = active ? 1 : 0; });
    return buf;
}

/** Decode 20-byte energy/threshold Buffer → { a: number[10], b: number[10] } */
function decodeEnergyBuffer(data) {
    const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
    const a = [], b = [];
    for (let i = 0; i < ZONE_COUNT; i++) {
        a.push(buf[i] ?? 0);
        b.push(buf[ZONE_COUNT + i] ?? 0);
    }
    return { a, b };
}

/** Encode two number[10] arrays (raw 0–255) → 20-byte Buffer. */
function encodeEnergyBuffer(arrA, arrB) {
    const buf = Buffer.alloc(20, 0);
    for (let i = 0; i < ZONE_COUNT; i++) {
        buf[i]              = Math.max(0, Math.min(255, Math.round(arrA[i] ?? 0)));
        buf[ZONE_COUNT + i] = Math.max(0, Math.min(255, Math.round(arrB[i] ?? 0)));
    }
    return buf;
}

// ─── fromZigbee ───────────────────────────────────────────────────────────────
const fzConverter = {
    cluster: TUYA_CLUSTER,
    type: ['commandDataResponse', 'commandDataReport'],
    convert(model, msg, publish, options, meta) {
        const result = {};

        for (const dpv of (msg.data?.dpValues ?? [])) {
            const { dp, data } = dpv;
            const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);

            switch (dp) {

                // ── DP1: Presence state ───────────────────────────────────────
                case DP.PRESENCE_STATE: {
                    const map = { 0: 'absence', 1: 'presence', 2: 'sensor_close' };
                    const state = map[buf[0]] ?? 'unknown';
                    result.presence_state = state;
                    result.occupancy = (state === 'presence');
                    break;
                }

                // ── DP2: Detection range ──────────────────────────────────────
                case DP.DETECTION_RANGE:
                    result.detection_range = buf.readUInt32BE(0);
                    break;

                // ── DP101: Illuminance ────────────────────────────────────────
                case DP.ILLUMINANCE:
                    result.illuminance = buf.readUInt32BE(0);
                    break;

                // ── DP102: Per-zone energy values (live, when streaming on) ───
                case DP.ENERGY_VALUE: {
                    if (buf.length < 20) break;
                    const { a: motion, b: presence } = decodeEnergyBuffer(buf);
                    for (let i = 0; i < ZONE_COUNT; i++) {
                        result[`zone_${i + 1}_motion_energy`]   = toApp(motion[i]);
                        result[`zone_${i + 1}_presence_energy`] = toApp(presence[i]);
                    }
                    break;
                }

                // ── DP103: Auto-calibration status ────────────────────────────
                case DP.AI_SELF_LEARNING: {
                    const map = { 0: 'standby', 1: 'start', 2: 'learning', 3: 'success', 4: 'fail', 5: 'cancel' };
                    result.auto_calibration_status = map[buf[0]] ?? 'unknown';
                    break;
                }

                // ── DP104: Energy streaming ack ───────────────────────────────
                case DP.HEARTBEAT_ENABLE:
                    result.energy_streaming = (buf[0] === 1);
                    break;

                // ── DP105: Device keepalive (no user-visible state) ───────────
                case DP.HEART:
                    break;

                // ── DP112: Sensitivity preset ─────────────────────────────────
                case DP.SENSITIVITY_PRESET: {
                    const map = { 0: 'high', 1: 'medium', 2: 'low', 3: 'custom' };
                    result.sensitivity_preset = map[buf[0]] ?? 'unknown';
                    break;
                }

                // ── DP117: Zone mode map ──────────────────────────────────────
                case DP.ZONE_MAP: {
                    if (buf.length < ZONE_COUNT) break;
                    for (let i = 0; i < ZONE_COUNT; i++) {
                        // 1 = active, 0 = blocked (shielded), 2 = treat as active
                        result[`zone_${i + 1}_active`] = (buf[i] !== 0);
                    }
                    break;
                }

                // ── DP119: Presence clear cooldown ────────────────────────────
                case DP.NO_PERSON_TIME:
                    result.presence_clear_cooldown = buf.readUInt32BE(0);
                    break;

                // ── DP123: LED indicator ──────────────────────────────────────
                case DP.INDICATOR:
                    result.led_indicator = (buf[0] === 1);
                    break;

                // ── DP124: Per-zone energy thresholds ─────────────────────────
                case DP.ENERGY_THRESHOLD: {
                    if (buf.length < 20) break;
                    const { a: motionThr, b: presenceThr } = decodeEnergyBuffer(buf);
                    // Cache raw values for safe read-modify-write in toZigbee
                    meta.device._lastThresholds = { motionThr: [...motionThr], presenceThr: [...presenceThr] };
                    for (let i = 0; i < ZONE_COUNT; i++) {
                        result[`zone_${i + 1}_motion_threshold`]   = toApp(motionThr[i]);
                        result[`zone_${i + 1}_presence_threshold`] = toApp(presenceThr[i]);
                    }
                    break;
                }

                default:
                    meta.logger.debug(`[ZPS-Z1] Unknown DP ${dp}: ${buf.toString('hex')}`);
            }
        }

        return result;
    },
};

// ─── toZigbee ─────────────────────────────────────────────────────────────────

const ZONE_ACTIVE_KEYS       = Array.from({ length: ZONE_COUNT }, (_, i) => `zone_${i + 1}_active`);
const ZONE_MOTION_THR_KEYS   = Array.from({ length: ZONE_COUNT }, (_, i) => `zone_${i + 1}_motion_threshold`);
const ZONE_PRESENCE_THR_KEYS = Array.from({ length: ZONE_COUNT }, (_, i) => `zone_${i + 1}_presence_threshold`);

const tzConverter = {
    key: [
        'detection_range',
        'sensitivity_preset',
        'presence_clear_cooldown',
        'led_indicator',
        'energy_streaming',
        'auto_calibration',
        ...ZONE_ACTIVE_KEYS,
        ...ZONE_MOTION_THR_KEYS,
        ...ZONE_PRESENCE_THR_KEYS,
    ],

    async convertSet(entity, key, value, meta) {
        const endpoint = meta.device.getEndpoint(1);

        // ── detection_range (DP2) ─────────────────────────────────────────────
        if (key === 'detection_range') {
            const clamped = Math.max(0, Math.min(500, Math.round(value / 50) * 50));
            const buf = Buffer.alloc(4);
            buf.writeUInt32BE(clamped, 0);
            await sendDP(endpoint, DP.DETECTION_RANGE, DT.VALUE, [...buf]);
            return { state: { detection_range: clamped } };
        }

        // ── sensitivity_preset (DP112) ────────────────────────────────────────
        if (key === 'sensitivity_preset') {
            const map = { high: 0, medium: 1, low: 2, custom: 3 };
            const val = map[value];
            if (val === undefined) throw new Error(`[ZPS-Z1] Invalid sensitivity_preset: ${value}`);
            await sendDP(endpoint, DP.SENSITIVITY_PRESET, DT.ENUM, [val]);
            return { state: { sensitivity_preset: value } };
        }

        // ── presence_clear_cooldown (DP119) ───────────────────────────────────
        if (key === 'presence_clear_cooldown') {
            const clamped = Math.max(2, Math.min(60, Math.round(value)));
            const buf = Buffer.alloc(4);
            buf.writeUInt32BE(clamped, 0);
            await sendDP(endpoint, DP.NO_PERSON_TIME, DT.VALUE, [...buf]);
            return { state: { presence_clear_cooldown: clamped } };
        }

        // ── led_indicator (DP123) ─────────────────────────────────────────────
        if (key === 'led_indicator') {
            const on = value === true || value === 'ON';
            await sendDP(endpoint, DP.INDICATOR, DT.BOOL, [on ? 1 : 0]);
            return { state: { led_indicator: on } };
        }

        // ── energy_streaming (DP104) ──────────────────────────────────────────
        if (key === 'energy_streaming') {
            const on = value === true || value === 'ON';
            await sendDP(endpoint, DP.HEARTBEAT_ENABLE, DT.BOOL, [on ? 1 : 0]);
            if (on) startKeepAlive(meta.device, endpoint);
            else stopKeepAlive(meta.device.ieeeAddr);
            return { state: { energy_streaming: on } };
        }

        // ── auto_calibration (DP103) ──────────────────────────────────────────
        if (key === 'auto_calibration') {
            const map = { start: 1, cancel: 5 };
            const cmd = map[value];
            if (cmd === undefined) throw new Error(`[ZPS-Z1] Invalid auto_calibration value: ${value}`);
            await sendDP(endpoint, DP.AI_SELF_LEARNING, DT.ENUM, [cmd]);
            return { state: {} };
        }

        // ── zone_N_active (DP117) ─────────────────────────────────────────────
        // Read-modify-write: update only the changed zone, preserve all others.
        if (ZONE_ACTIVE_KEYS.includes(key)) {
            const zoneIdx = parseInt(key.split('_')[1], 10) - 1;
            const active  = value === true || value === 'ON';
            const zones   = currentZoneArray(meta);
            zones[zoneIdx] = active;
            const buf = encodeZoneMap(zones);
            await sendDP(endpoint, DP.ZONE_MAP, DT.RAW, [...buf]);
            const stateUpdate = {};
            zones.forEach((a, i) => { stateUpdate[`zone_${i + 1}_active`] = a; });
            return { state: stateUpdate };
        }

        // ── zone_N_motion_threshold (DP124) ───────────────────────────────────
        // Value arrives as 0–100; convert to raw 0–255 before sending.
        if (ZONE_MOTION_THR_KEYS.includes(key)) {
            const zoneIdx = parseInt(key.split('_')[1], 10) - 1;
            const cached  = meta.device._lastThresholds;
            const state   = meta.state ?? {};
            const motionThr   = cached
                ? [...cached.motionThr]
                : Array.from({ length: ZONE_COUNT }, (_, i) => toRaw(state[`zone_${i + 1}_motion_threshold`]   ?? 50));
            const presenceThr = cached
                ? [...cached.presenceThr]
                : Array.from({ length: ZONE_COUNT }, (_, i) => toRaw(state[`zone_${i + 1}_presence_threshold`] ?? 50));
            motionThr[zoneIdx] = toRaw(Math.max(0, Math.min(100, Math.round(value))));
            const buf = encodeEnergyBuffer(motionThr, presenceThr);
            await sendDP(endpoint, DP.ENERGY_THRESHOLD, DT.RAW, [...buf]);
            await new Promise((r) => setTimeout(r, 150));
            await sendDP(endpoint, DP.SENSITIVITY_PRESET, DT.ENUM, [3]);
            const stateUpdate = { sensitivity_preset: 'custom' };
            motionThr.forEach((v, i)   => { stateUpdate[`zone_${i + 1}_motion_threshold`]   = toApp(v); });
            presenceThr.forEach((v, i) => { stateUpdate[`zone_${i + 1}_presence_threshold`] = toApp(v); });
            return { state: stateUpdate };
        }

        // ── zone_N_presence_threshold (DP124) ─────────────────────────────────
        if (ZONE_PRESENCE_THR_KEYS.includes(key)) {
            const zoneIdx = parseInt(key.split('_')[1], 10) - 1;
            const cached  = meta.device._lastThresholds;
            const state   = meta.state ?? {};
            const motionThr   = cached
                ? [...cached.motionThr]
                : Array.from({ length: ZONE_COUNT }, (_, i) => toRaw(state[`zone_${i + 1}_motion_threshold`]   ?? 50));
            const presenceThr = cached
                ? [...cached.presenceThr]
                : Array.from({ length: ZONE_COUNT }, (_, i) => toRaw(state[`zone_${i + 1}_presence_threshold`] ?? 50));
            presenceThr[zoneIdx] = toRaw(Math.max(0, Math.min(100, Math.round(value))));
            const buf = encodeEnergyBuffer(motionThr, presenceThr);
            await sendDP(endpoint, DP.ENERGY_THRESHOLD, DT.RAW, [...buf]);
            await new Promise((r) => setTimeout(r, 150));
            await sendDP(endpoint, DP.SENSITIVITY_PRESET, DT.ENUM, [3]);
            const stateUpdate = { sensitivity_preset: 'custom' };
            motionThr.forEach((v, i)   => { stateUpdate[`zone_${i + 1}_motion_threshold`]   = toApp(v); });
            presenceThr.forEach((v, i) => { stateUpdate[`zone_${i + 1}_presence_threshold`] = toApp(v); });
            return { state: stateUpdate };
        }

        meta.logger.warn(`[ZPS-Z1] convertSet: unhandled key "${key}"`);
    },

    async convertGet(entity, key, meta) {
        // TS0601 Tuya devices do not support ZCL attribute reads for DPs.
        // State is populated via the dataQuery in configure().
    },
};

// ─── Expose builders ──────────────────────────────────────────────────────────

const e  = require('zigbee-herdsman-converters/lib/exposes');
const ea = e.access;

function buildZoneActiveExposes() {
    return Array.from({ length: ZONE_COUNT }, (_, i) =>
        e.binary(`zone_${i + 1}_active`, ea.ALL, true, false)
            .withDescription(`${i * 50}\u2013${(i + 1) * 50}cm`),
    );
}

function buildEnergyExposes() {
    const items = [];
    for (let i = 1; i <= ZONE_COUNT; i++) {
        items.push(
            e.numeric(`zone_${i}_motion_energy`, ea.STATE)
                .withDescription(`Zone ${i} live motion energy (0–100).`)
                .withValueMin(0).withValueMax(100)
                .withCategory('diagnostic'),
            e.numeric(`zone_${i}_presence_energy`, ea.STATE)
                .withDescription(`Zone ${i} live presence energy (0–100).`)
                .withValueMin(0).withValueMax(100)
                .withCategory('diagnostic'),
        );
    }
    return items;
}

function buildThresholdExposes() {
    const items = [];
    for (let i = 1; i <= ZONE_COUNT; i++) {
        items.push(
            e.numeric(`zone_${i}_motion_threshold`, ea.ALL)
                .withDescription(`Zone ${i} motion trigger threshold (0–100). Switches sensitivity to custom.`)
                .withValueMin(0).withValueMax(100).withValueStep(1),
            e.numeric(`zone_${i}_presence_threshold`, ea.ALL)
                .withDescription(`Zone ${i} presence trigger threshold (0–100). Switches sensitivity to custom.`)
                .withValueMin(0).withValueMax(100).withValueStep(1),
        );
    }
    return items;
}

// ─── Device definition ────────────────────────────────────────────────────────
const definition = {
    zigbeeModel: ['TS0601'],
    model: 'ZPS-Z1',
    vendor: 'Zemismart',
    description: '24 GHz mmWave presence sensor',
    fromZigbee: [fzConverter],
    toZigbee: [tzConverter],

    onEvent: async (type, data, device) => {
        if (type === 'deviceLeave' || type === 'deviceRemoved') {
            stopKeepAlive(device.ieeeAddr);
        }
    },

    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await endpoint.bind(TUYA_CLUSTER, coordinatorEndpoint);
        await endpoint.command(TUYA_CLUSTER, 'dataQuery', {}, { disableDefaultResponse: true });
        const log = logger?.debug ?? logger?.info ?? logger?.log ?? (() => {});
        log('[ZPS-Z1] Configured — initial state query sent.');
    },

    exposes: [
        // ── Primary presence & light ──────────────────────────────────────────
        e.binary('occupancy', ea.STATE, true, false)
            .withDescription('Binary presence detection. Person detected (true) or not detected (false).'),

        e.enum('presence_state', ea.STATE, ['absence', 'presence', 'sensor_close'])
            .withDescription(
                'absence — no one detected. ' +
                'presence — person detected. ' +
                'sensor_close — detection zone is physically obstructed or sensor is disabled.',
            ),

        e.numeric('illuminance', ea.STATE)
            .withUnit('lx')
            .withDescription('Ambient light level (0–1300 lx).')
            .withValueMin(0).withValueMax(1300),

        // ── Detection tuning ──────────────────────────────────────────────────
        e.numeric('detection_range', ea.ALL)
            .withUnit('cm')
            .withDescription('Maximum radar detection distance (0–500 cm, 50 cm steps). Firmware limits radar distance to 500 cm (5 meters).')
            .withValueMin(0).withValueMax(500).withValueStep(50),

        e.numeric('presence_clear_cooldown', ea.ALL)
            .withUnit('s')
            .withDescription('Presence clear time before the sensor switches state to "absence". (2–60 s).')
            .withValueMin(2).withValueMax(60).withValueStep(1),

        e.enum('sensitivity_preset', ea.ALL, ['high', 'medium', 'low', 'custom'])
            .withDescription(
                '"high" — detects subtle movement and stationary presence. ' +
                '"medium" — balanced default. ' +
                '"low" — only strong or close-range activity triggers detection. ' +
                '"custom" — per-zone thresholds active (set automatically when any zone threshold is written).',
            ),

        // ── Auto-calibration ──────────────────────────────────────────────────
        e.enum('auto_calibration', ea.SET, ['start', 'cancel'])
            .withDescription(
                'Trigger AI self-learning to auto-tune thresholds for your environment. ' +
                'Set to "start", leave the room for ~60 s, then check auto_calibration_status. ' +
                'Allow 5–10 minutes of sensor warm-up before first calibration run.',
            ),

        e.enum('auto_calibration_status', ea.STATE, ['standby', 'start', 'learning', 'success', 'fail', 'cancel'])
            .withDescription(
                '"standby" — idle. "start" — initiated. "learning" — in progress. ' +
                '"success" — thresholds updated. "fail" — failed. "cancel" — stopped by user.',
            ),

        // ── LED indicator ─────────────────────────────────────────────────────
        e.binary('led_indicator', ea.ALL, true, false)
            .withDescription('Physical LED indicator of the sensor.'),

        // ── Real-time energy streaming ────────────────────────────────────────
        e.binary('energy_streaming', ea.ALL, true, false)
            .withDescription(
                'Enable diagnostic per-zone radar energy reporting. ' +
                'Turn ON only when tuning thresholds, turn OFF when done to reduce Zigbee traffic.',
            ),

        // ── Per-zone live energy (DP102, diagnostic) ──────────────────────────
        ...buildEnergyExposes(),

        // ── Zone active toggles (DP117) ───────────────────────────────────────
        ...buildZoneActiveExposes(),

        // ── Per-zone thresholds (DP124) ───────────────────────────────────────
        ...buildThresholdExposes(),
    ],

    meta: {
        tuyaDatapoints: null, // custom fz/tz above; disable built-in Tuya DP handler
    },
};

module.exports = definition;
保存,重启 z2m,就可以看到传感器被识别了
iShot_2026-06-17_11.42.05.png
因为我想测试涂鸦的自主学习,所以 z2m 没有用太长时间,具体功能设置可能需要各位自行研究或者其他测评者详细研究了。
以上就是我拿到人体存在传感器的使用体验
四、总结
个人感受:
1、设备确实很小巧,安装到墙上也不是很违和。尤其是磁吸,真的太方便了,想怎么调角度就怎么调。而且可调范围很大。
2、感应很灵敏,目前用下来几乎可以实现人来开灯的效果,状态变化时,led 会闪一下,感觉关闭这个可能会增加电池使用时间把。(我之前用的人体存在是装在吊顶,猫狗活动也会判断有人,猜测这个传感器可以通过自主学习把猫狗的活动排除掉)PS:还有一个,我测试的时候一开始就放在电脑桌上,离人很近,那判断有问题,后来放在洞洞板上,就没出现不能判断的问题了。猜测是距离太近,传感器也不是很好识别,
3、有光照传感器,可以根据光照来设置自动化,同时我更希望可以自带温湿度传感器(这样我这个区域就不用再装一个温湿度传感器了)

今天就先这样啦,用几天排除一下能量少的再看看是不是猫狗就不会被触发了。
IMG_7626.jpeg
IMG_7625.jpeg
IMG_7624.jpeg
IMG_7622.jpeg
IMG_7621.jpeg
iShot_2026-06-17_11.42.14.png
iShot_2026-06-17_11.36.40.png
iShot_2026-06-17_11.36.36.png
回复

使用道具 举报

0

主题

3

回帖

14

积分

新手上路

积分
14
金钱
11
HASS币
0
发表于 2026-6-27 18:33:48 | 显示全部楼层
放在电脑桌子上边,如果旁边靠显示太近 或者附近有些金属,可能会造成一些雷达信号的问题。
回复

使用道具 举报

10

主题

359

回帖

4938

积分

论坛元老

积分
4938
金钱
4569
HASS币
0
 楼主| 发表于 2026-6-28 13:01:43 | 显示全部楼层
zemiwilliam2026 发表于 2026-6-27 18:33
放在电脑桌子上边,如果旁边靠显示太近 或者附近有些金属,可能会造成一些雷达信号的问题。 ...

是的,发现这个问题了,最终我还是放在了高处顶装
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|Hassbian ( 晋ICP备17001384号-1 )|网站地图

GMT+8, 2026-7-18 20:00 , Processed in 0.269579 second(s), 4 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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