jimmywarting / wemo-client

JavaScript client library for controlling and subscribing to Wemo Devices
MIT License
132 stars 40 forks source link

Event client.on attributeList for Wemo Maker sleeping ? #31

Closed dircm closed 8 years ago

dircm commented 8 years ago

When no events have been emitted for a long while ( > 6 hours), client.on is not catching any events and my code needs to be restarted to get events caught again.

Wemo Maker is setup as normal on/off and sensor set to receive active low.

Here is my code from a HAPNode (Homekit) Gate project:

var Accessory = require('../').Accessory;
var Service = require('../').Service;
var Characteristic = require('../').Characteristic;
var uuid = require('../').uuid;

var Wemo = require('/home/pi/node_modules/wemo-client/index');
var wemo = new Wemo();
var gateclient; //wemo-client client object needs to be global to be useful.

    function tm(unix_tm) {
        var dt = new Date(unix_tm*1000);
        console.log(dt.getHours() + '/' + dt.getMinutes() + '/' + dt.getSeconds() + ' -- ' + dt + '<br>');
    }

// here we bind the the Wemo Maker called Front gate and run a small test
function bindDevice(device) {
  if (device.friendlyName === "Front gate") {  //lets just check to see if we have the right wemo
    console.log('Connected to: %s', device.friendlyName);

    gateclient = this.client(device);
    gateclient.on('attributeList', function(name, value, prevalue, timestamp) {
      console.log('Wemo "%s" changed %s from %s to %s at %s', this.device.friendlyName, name, prevalue, value, timestamp);
      tm(timestamp);
      if (name === "Sensor"){
        if (value === "0"){
        // now we want to set our gate's "actual state" to be unsecured so it shows as unlocked in iOS apps
        gate
          .getService(Service.LockMechanism)
          .setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.UNSECURED);
        GATE_LOCK.locked = false;
        console.log('GATE_LOCK.locked set to %s', GATE_LOCK.locked)
        } else {
          // now we want to set our gate's "actual state" to be secured so it shows as locked in iOS apps
        gate
          .getService(Service.LockMechanism)
          .setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.SECURED);
        GATE_LOCK.locked = true;
        console.log('GATE_LOCK.locked set to %s', GATE_LOCK.locked)
        }
      }
    });
  }
}

wemo.load("http://192.168.178.32:49153/setup.xml", bindDevice);
console.log('Loading Wemo Maker at 192.168.178.32:49153');

// here's a fake hardware device that we'll expose to HomeKit
var GATE_LOCK = {
  locked: true,
  lock: function() { 
    console.log("Locking the gate!");
    gateclient.setBinaryState(0);
  },
  unlock: function() { 
    console.log("Unlocking the gate!");
    gateclient.setBinaryState(1);
  },
  identify: function() {
    console.log("Identify the gate!");
    setTimeout(function() { gateclient.setBinaryState(1); }, 3 * 1000);
    setTimeout(function() { gateclient.setBinaryState(0); }, 6 * 1000);
  }
}

// Generate a consistent UUID for our Lock Accessory that will remain the same even when
// restarting our server.
var lockUUID = uuid.generate('hap-nodejs:accessories:garage');

// This is the Accessory that we'll return to HAP-NodeJS that represents our gate.
var gate = exports.accessory = new Accessory('Gate', lockUUID);

// Add properties for publishing (in case we're using Core.js and not BridgedCore.js)
gate.username = "C1:5D:3A:EE:5A:FA";
gate.pincode = "031-45-154";

// set some basic properties (these values are arbitrary and setting them is optional)
gate
  .getService(Service.AccessoryInformation)
  .setCharacteristic(Characteristic.Manufacturer, "White")
  .setCharacteristic(Characteristic.Model, "Rev-1")
  .setCharacteristic(Characteristic.SerialNumber, "TW0001");

// listen for the "identify" event for this Accessory
gate.on('identify', function(paired, callback) {
  GATE_LOCK.identify();
  callback(); // success
});

// Add the actual Door Lock Service and listen for change events from iOS.
// We can see the complete list of Services and Characteristics in `lib/gen/HomeKitTypes.js`
gate
  .addService(Service.LockMechanism, "Gate Lock") 
  .setCharacteristic(Characteristic.LockTargetState, Characteristic.LockTargetState.SECURED)
  .setCharacteristic(Characteristic.LockCurrentState, Characteristic.LockCurrentState.SECURED)
  .getCharacteristic(Characteristic.LockTargetState)
  .on('set', function(value, callback) {

    if (value == Characteristic.LockTargetState.UNSECURED) {
      GATE_LOCK.unlock();
      callback(); // Our Lock is synchronous - this value has been successfully set

    }
    else if (value == Characteristic.LockTargetState.SECURED) {
      GATE_LOCK.lock();
      callback(); // Our Lock is synchronous - this value has been successfully set

    }
  });

// We want to intercept requests for our current state so we can query the hardware itself instead of
// allowing HAP-NodeJS to return the cached Characteristic.value.
gate
  .getService(Service.LockMechanism)
  .getCharacteristic(Characteristic.LockCurrentState)
  .on('get', function(callback) {

    // this event is emitted when you ask Siri directly whether your gate is locked or not. you might query
    // the gate hardware itself to find this out, then call the callback. But if you take longer than a
    // few seconds to respond, Siri will give up.

    var err = null; // in case there were any problems

    if (GATE_LOCK.locked) {
      console.log("Query: Is Gate locked? Yes.");
      callback(err, Characteristic.LockCurrentState.SECURED);
    }
    else {
      console.log("Query: Is Gate locked? No.");
      callback(err, Characteristic.LockCurrentState.UNSECURED);
    }
  });
timonreinhard commented 8 years ago

Thanks for using wemo-client and giving feedback. Can you provide the firmware version of your Wemo Maker device?

dircm commented 8 years ago

UPDATE: Ran some tests with the Wemo Maker sending events to IFTTT. It seems the Wemo Maker is only sending one or the other (Sensor or Switch) events to IFTTT if I trigger both at same time. This is not ideal but does isolate the issue away from wemo-client code issues.

UPDATE2: Ran the new "maker.js" example test code (0.6.6), I only get one type of event when the Maker triggers both a Sensor AND Switch events at the same time.

WeMo_WW_2.00.10061

Also seeing events missed such as tripping a maker on ("Switch" event) and sensor ("Sensor" event) at same time. I'm running some more tests to see if the maker is sending these events to IFTTT for troubleshooting and will post here.

timonreinhard commented 8 years ago

Regarding the issue with only one event sent for two trigger happen both at the same time: A fix is on it's way included in 0.7.0.

The issue originally mentioned seems a bit tricky, though. Can you still control the device (using the library) when it's no longer sending events?

dircm commented 8 years ago

Wow, thats a fast release!

I'll try 0.7.0 shortly.

Devices can still be controlled no problem. My guess is the dropped events were caused by the wemo hardware or wemo-client not handling synchronous events. I'll update shortly.

dircm commented 8 years ago

Hi Timon, the synchronous events are being caught and handled perfectly in 0.7.0 and the 0.6.6 code functioned for over 12 hours and then caught an event. Thanks for the work! Tom.

I'll close this.

dircm commented 8 years ago

Hi Timon, I had another case of events "sleeping" for one of my Wemo Makers. As with before, I could still set State fine but never got sensor or state change events. I have implemented a basic 3 hourly watchdog timer using setInterval() that performs a client.getAttributes() in attempt to keep the event subscription alive. I'll let you know how this goes after a few days. Tom.

dircm commented 8 years ago

I had another "sleeping" client.on from my Wemo Lightswitch after 25 hours.

Is there any way I can "unload" my Wemo bindings to refresh the device subscription ? Or can I just overwrite the device with another call to Wemo.load() ?

I'm trying to implement a watchdog to keep these events coming through.

Thanks, Tom.

timonreinhard commented 8 years ago

Any chance the event handling recovers after polling the attributes with getAttributes?

The subscriptions need a refactoring anyway. I'll come up with a solution that also covers destroying and recreating clients with the next release.

timonreinhard commented 8 years ago

18

dircm commented 8 years ago

Any chance the event handling recovers after polling the attributes with getAttributes?

No, I have been polling the lightswitch every hour with a simple getAttributes call run off a setInterval timer...

timonreinhard commented 8 years ago

Did you already run with env DEBUG=wemo-client? If so, there should be a console message like Renewing subscription… about every 2 minutes. In case something went wrong, you'll see an error message like HTTP Error (…) occurred (re)subscribing to Wemo Device…. This should help getting your issue sorted.