Oplossing voor sonoff zigbee mini dim

Heeft iemand al een oplossing om een zigbee mini dim van Sonoff toe te voegen aan de homey pro?

Je zou de Sonoff ZBBridge kunnen proberen, deze is via de eWeLink app te integreren met Homey.

Naast de ZBBridge kan je met een Sonoff iHost met Homeyscrpt gegevens uitwisselen*, ook kan je met Zigbee2MQTT en een Rasberry Pi Zigbee devices delen.
Deze methodes vrijwaren je van de notoire Zigbee problemen met Homey.

  • Script voorbeeld functie voor iHost communicatie via http (let oResp = await fetch(IHOST_URL … :
// setVirtualDevic
async function setVirtualDevices() {
  let bResult = false; // default return
  let iSuccessCount = 0;
  let uValue = NO_VALUE;
  let aResult = [];
  try {
    // Only process specific capabilities;
    const oCapMapping = new Map([
      ['temperature', 'Temp'],
      ['humidity', 'Hum'],
      ['illumination', 'Lux'],
      ['smoke', 'Smoke'],
      ['power', 'Power']
    ]);

    // HomeyScript - Write iHost values to Device Capabilities Virtual Devices (direct mutation)
    let oResp = await fetch(IHOST_URL, {
      headers: {
        'Authorization': 'Bearer ' + TOKEN,
        'Content-Type': 'application/json'
      }
    });

    let oResult = await oResp.json();
    let aDevices = oResult.data.device_list || [];
    // sort
    aDevices.sort();  // Alphabetical order

    if (DO_LOG)
      log('Found ' + aDevices.length + ' iHost devices');

    for (let iDevice = 0; iDevice < aDevices.length; iDevice++) {
      let oDevice = aDevices[iDevice];
      let sDeviceName = oDevice.name || 'Unknown';

      if (DEV_SKIP.includes(sDeviceName)) {
        /* if (DO_LOG)
          log(`DEV_SKIP found and skipped:${sDeviceName}`);*/
        continue;  // skip this device
      }

      uValue = NO_VALUE; // (re)set

      if (DO_LOG_X)
        log('--- Processing iHost Device: ' + sDeviceName + ' --- ' + JSON.stringify(oDevice.capabilities));


      // Find Virtual Device by EXACT name match using global
      const oVirtualDevice = VIRTUALDEVICES.find(device =>
        device.name === sDeviceName.trim()
      ) || null;


      if (!oVirtualDevice || !oVirtualDevice.id || !oVirtualDevice.capabilitiesObj) {
        // if (DO_LOG)
        log('  No matching Virtual Device found: ' + sDeviceName);
        continue;
      }
      if (DO_LOG_X)
        log(`  Found Virtual Device: ${oVirtualDevice.name} (${oVirtualDevice.id})`);

      let aCapabilities = oDevice.capabilities || [];
      let oState = oDevice.state || {};

      for (let iCap = 0; iCap < aCapabilities.length; iCap++) {
        let oCap = aCapabilities[iCap];
        let sOriginalCapName = oCap.capability;  // iHost: 'temperature' 'humidity' 'illumination' 'smoke' 'power'

        if (!oCapMapping.has(sOriginalCapName)) { // skip not supported Capability
          /* if (DO_LOG)
            log(`EXIT - CAPABILITY not found: ${sOriginalCapName}`);*/
          continue;
        }

        // Extract value from iHost state using ORIGINAL iHost name
        if (oState[sOriginalCapName]) {
          if (typeof oState[sOriginalCapName] === 'object' &&
            oState[sOriginalCapName][sOriginalCapName] !== undefined) {
            uValue = oState[sOriginalCapName][sOriginalCapName];
          } else {
            uValue = oState[sOriginalCapName];
          }
        }
        // log(`sDeviceName: ${sDeviceName} ${JSON.stringify(uValue)}`);
        //-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
        // TOGGLE
        //-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!

        const oChannels = Object.keys(uValue).filter(key => {
          // Numeric key 1-4 AND has toggleState property
          return !isNaN(key) && key >= "1" && key <= "4" &&
            uValue[key] &&
            typeof uValue[key] === 'object' &&
            uValue[key].hasOwnProperty('toggleState');
        });
        // log(`oChannels:${oChannels}`)
        let oAllToggles = {};

        // power
        if ((sOriginalCapName === 'toggle' || sOriginalCapName === 'power')) {
          // uValue === NO_VALUE &&  || sOriginalCapName === 'onoff'
          uValue = (oState?.power?.powerState === 'on');
          /*if (DO_LOG)
            log(`0 POWER ... uValue:${uValue} sOriginalCapName:${sOriginalCapName} sDeviceName:${sDeviceName}`);*/
        }
        else if (sOriginalCapName === 'toggle' && oChannels) {
          // console.log(`channels: ${oChannels}`); // ["1", "2", "3", "4"]
          oAllToggles = Object.values(uValue).map(item => item.toggleState);

          uValue = oAllToggles.join(';');

          if (uValue !== ';' && DO_LOG_X)
            log(`1 TOGGLE ... uValue:${JSON.stringify(uValue)} sOriginalCapName:${sOriginalCapName} sDeviceName:${sDeviceName}`);
        }

        //-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
        // END TOGGLE
        //-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!

        // Handle uValue
        if (sDeviceName.startsWith('$net') && DO_LOG) { // NET -- && variablename includes _Power'
          log(`NET - sDeviceName:${sDeviceName} uValue:${uValue}`);
        }

        const sType = typeof uValue;

        // Handle missing binary states → default false
        if (uValue === NO_VALUE && ['smoke', 'motion'].includes(sOriginalCapName)) {
          uValue = false; // might be NO_VALUE No smoke No motion
        }
        else if (['toggle', 'power'].includes(sOriginalCapName)) { // 'onoff',  uValue === NO_VALUE &&
          // log(`$$$$$$$$$$$$$ toggle sDeviceName:${sDeviceName} uValue:${uValue}`)
          uValue = isBool(uValue); // Boolean
        } else if (sType === 'boolean') { // Boolean
          // Do nothing - Keep boolean as-is (true/false)
        } else if (sType === 'number') {
          uValue = parseFloat(uValue); // Number
        } else {
          uValue = String(uValue); // String
        }

        if (uValue === NO_VALUE) {
          // sendPush(`${DATE} ${TIME} - iHostGet1: ${sDeviceName} with capability:${sOriginalCapName}: STILL NOTHING FOUND: "${uValue}"`)
          continue; // STILL NOTHING FOUND
        }

        // sDeviceNameCap is sDeviceName + capability extension as sCapIdentifier see: iHostGet1Help
        const sDeviceNameCap = `${sDeviceName}_${sOriginalCapName[0].toLowerCase()}`; // + _h, _t, _s, _i, _o, _p

        // Get ID first
        const sVarId = getVarId(sDeviceNameCap);
        if (DO_LOG_X)
          log(`sDeviceNameCap:${sDeviceNameCap} sOriginalCapName:${sOriginalCapName[0].toLowerCase()}  sVarId: ${sVarId}  uValue: ${uValue};`);

        if (sVarId !== null) { //  && uValue !== NO_VALUE
          try {
            // SET VARIABLE BY ID FROM DEVICE NAME . VAR_MAP . getVarId
            if (DO_LOG_X)
              log(`SET VARIABLE BY DEVICE ${sDeviceName} = ${uValue}`);

            bResult = await setVariable(sVarId, uValue);

            if (bResult) {
              iSuccessCount++;
              if (DO_LOG_X)
                log(`  ${sOriginalCapName}: ${uValue}`);
            } else {
              log(`  ${sOriginalCapName} failed`);
            }
          } catch (oError) {
            log(`${sOriginalCapName}: ${oError.message}`);
          }
        } else {
          log(`${sOriginalCapName}: No variable Found for sDeviceNameCap:${sDeviceNameCap}  uValue:"${uValue}"`);
          // sendPush(`${DATE} ${TIME} - iHostGet1: ${sOriginalCapName}: invalid value: "${uValue}"`)
        }
      }

      // bResult = true;

      // MESSAGE BLOCK
      if (sDeviceName.startsWith('rook') && uValue === true) { // Rook ALARM
        log(`ALARM - sDeviceName:${sDeviceName} uValue:${uValue}`);
        // sendPush(`${DATE} ${TIME} - iHostGet1 - ROOK ALARM - sDeviceName:${sDeviceName} uValue:${uValue}`);
      }
      else if (sDeviceName.startsWith('$net') && uValue === false) { // Error NET'
        log(`NET - sDeviceName:${sDeviceName} uValue:${uValue}`);
        // sendPush(`${DATE} ${TIME} - iHostGet1 - NET ALARM - sDeviceName:${sDeviceName} uValue:${uValue}`);
      }

      aResult.push(`--- Done: ${sDeviceName} ---  ${uValue}`);
    }

  } catch (oError) {
    log(`setVirtualDevices failed: ${oError.message}`);
    return false;
  }

  aResult = aResult.sort();
  if (DO_LOG)
    log(aResult.join('\n'));
  return true; // bResult;
}

1 Like

Of eWeLink CUBE op een Raspberry Pi met ZigBee dongle (iHost werkt op hetzelfde OS voor zover ik weet)