roblans / ZWave4Net

ZWave4Net is a .NET library that interfaces with the Aeotec / Aeon Labs Z-Stick.
MIT License
41 stars 33 forks source link

WallPlug class gets timeouts #27

Closed Kla3mus closed 5 years ago

Kla3mus commented 5 years ago

Hi!

First off I would like to say that i like the general style the library is made in. I have a couple of questions tho.

I have some Fibaro WallPlugs (FGWPE/F-102 ZW5) and I found a class in the Fibaro folder that's called WallPlug. I wrote the following:

var wallPlug = new WallPlug(node);

var blah1 = await wallPlug.GetEnergyConsumption(); //Works
var blah2 = await wallPlug.GetLedRingColorOff(); //Does not work
var blah3 = await wallPlug.GetLedRingColorOn();  //Does not work
var blah4 = await wallPlug.GetMeasureInterval();  //Does not work
var blah5 = await wallPlug.GetPowerLoadChangeReporting(); //Works
var blah6 = await wallPlug.GetPowerLoad(); //Works

await wallPlug.SetLedRingColorOn(WallPlug.LedRingColorOn.Green); //Does not work

I also found that this class did not follow the same pattern as the general classes, where you normally (as far as i could deduce) go something like this:

var meter = node.GetCommandClass<Meter>();
meter.Changed += (sender, args) =>
{
    Console.WriteLine($"METER: {args.Report.Type} {args.Report.Value} {args.Report.Unit}");
};

And call meter.Get(ElectricMeterScale.W); whenever you want it to return a value (possibly creating a task that handles this and reports back to main thread everytime a new value has occured).

The questions go something like this:

  1. Why is the design so different in the Fibaro WallPlug class from the standard classes?
  2. How come so many of the methods in the WallPlug class does not work?
  3. Am I using the WallPlug class wrong? I see many of them inherit from Device.. but I can't seem to understand how to use it properly (?)
  4. I have a AeoTec Multisensor 6 ZW100 and was wondering if I should make support for it in your library.. but if i am to do that, i should probably understand how you'd prefer that to be done first :)
roblans commented 5 years ago

Hi

  1. Why is the design so different in the Fibaro WallPlug class from the standard classes?

The library provides two programming models to interact with ZWave. There is a (generic) low-level approach which deals with Nodes and CommandClasses. This approach will work with all available ZWave devices. But you have to now what CommandClasses are implemented for a particular device. The (specific) high-level approach deals with strong typed devices (classes derived of the Device baseclass). These classes will only expose methods that are available and implemented.

Suppose you want to set the color of the fibaro wallplug color to Red:

low-level generic: await node.GetCommandClass<Configuration>().Set(61, 3);

high-level specific: await wallPlug.SetLedRingColorOn(WallPlug.LedRingColorOn.Red);

The high-level code is much clearer to read. Unfortunately it's impossible for me to provide an implementation for every ZWave device on the market. You're happy to contribute to this library.

  1. How come so many of the methods in the WallPlug class does not work?

That's weird, I'm using the same WallPlug (I will do some more testing with this Device). Do you have exception details on the error your getting?

  1. Am I using the WallPlug class wrong?

No, seems fine to me

  1. AeoTec Multisensor 6 ZW100

This device is already part of the library: ZWave.Devices.Aeon.MultiSensor6

roblans commented 5 years ago

Did some testing with the wallplug

var blah1 = await wallPlug.GetEnergyConsumption(); //Works
var blah2 = await wallPlug.GetLedRingColorOff(); //Works
var blah3 = await wallPlug.GetLedRingColorOn();  //Works
var blah4 = await wallPlug.GetMeasureInterval();  //**Does not work**
var blah5 = await wallPlug.GetPowerLoadChangeReporting(); //Works
var blah6 = await wallPlug.GetPowerLoad(); //Works
roblans commented 5 years ago

Bug in: wallPlug.GetMeasureInterval() Fixed.

Kla3mus commented 5 years ago

Hi again! :)

Awesome with the multisensor! I tried it, but I'm struggeling to get any events fireing. When i went the low level way with the SensorMultiLevel class, i ran a Get() on the command class and the events would pop, but I can't seem to find a similar method on MultiSensor6 to force the update. In the beginning i figured that the class itself would find out when to do these events, because of .GetWakeUpInterval() and so forth, but i suppose waking up is ment for something else?

The WallPlug fires events when I run the var value = await wallPlug.GetEnergyConsumption();. The value is also returned from the method. Is it ment to be used without retreiving the value from the method?

On the WallPlug I still get timeout errors on await wallPlug.GetLedRingColorOff(), and the others alike. I went into the ZWaveChannel.cs and found that on line 505 it throws a TimeOutException if the CancellationToken says it's a canceled request, which in my case it gets to be. I debugged it and the Original Exception Message is; "A task was canceled".. Not sure why this would be but... I also tried to run this, low level like you showed: await node.GetCommandClass<Configuration>().Set(61, 3); It still fails with TimeOutException...

The node I am putting into the constructor of WallPlug is the one it finds from controller.GetNodes();. In MultiSensor6, using low level, the methods I call seems to be working ok, could it be with the pairing? or something else? Is it possible that i have a different version of it? I was reading a bit here -> https://manuals.fibaro.com/wall-plug/ and i found that there seems to be two different sets. above 3.2 and 2.5 or lower.. whatever that means. It seems they have, sort of, different features..

Kla3mus commented 5 years ago

Also.. when I run WallPlug.SwitchedOn() the event wallPlug.SwitchedOff is fired....

roblans commented 5 years ago

MultiSensor6

The MultiSensor6 is a battery operated device, these devices are normally asleep (to save battery lifetime). When a device is asleep it won't respond to commands. Battery operated devices supports a 'WakeUp' commandclass, with this class you can configure a wakeup interval. The device will then wakeup periodically and send a event. During this event you can communicate with the device. You can also force a manually wakeUp by pressing the buttons on the device.

To get readings from the multisensor just subcribe to the events (MotionDetected, TemperatureMeasured, ...). The Configuration commandclass can be used to change the parameters for sending the events (see manual).

WallPlug

Yes, most 'Get' methods also trigger an event. Just use the return value from the method.

Oh, now I get it, it is indeed a firmware version. Seems like Fibaro simply updated the firmware and changed a bunch of configuration parameters.

2.1-2.5: await node.GetCommandClass().Set(61, 3) 3.2: await node.GetCommandClass().Set(41, 3)

Kla3mus commented 5 years ago

MultiSensor6

Does that mean that if i am to use the MultiSensor6 class, i also have to use the low-level WakeUp class, to force it to wake up? When i check await sensor.GetWakeUpInterval(); i get 00:00:00, which sort of makes sense... It should not sleep when being powered by USB...? How often should i then expect it to fire measuring events? Or do i have to do a Get on the low level command classes?

The sensor also supports a USB cable (which i am using atm), hence some of my confusion..

The Configuration commandclass can be used to change the parameters for sending the events (see manual).

which manual are you referring to here?

WallPlug

How are you finding the different values to apply? If you have some place with documentation I could create a new WallPlug class for Fibaro that supports the new firmware... I have been trying to search for these, but to no avail. I did find the document for the ZWave specifications, but I suppose those describe the low-level classes, and not the particulars for every ZWave device

roblans commented 5 years ago

MultiSensor6

If it's powered by USB you should be able to get the readings at any time by calling: var report = await Node.GetCommandClass<SensorMultiLevel>().Get(SensorType type);

To make things easier I've added extra methods to the MultiSensor6 class:

            var device = new ZWave.Devices.Aeon.MultiSensor6(node);
            var temperature = await device.GetTemperature();
            var relativeHumidity = await device.GetRelativeHumidity();
            var ultraviolet = await device.GetUltraviolet();
            var luminance = await device.GetLuminance();

Advanced configuration parameters are described in this manual: https://aeotec.freshdesk.com/helpdesk/attachments/6053297241

WallPlug

I've updated the code for the WallPlug, it's now compatible with the new firmware. For older firmware you can pass an extra FirmwareVersion to the constructor.

public WallPlug(Node node, FirmwareVersion version = FirmwareVersion.Latest)

The correct configuration parameters are described in:

9: Advanced parameters

https://manuals.fibaro.com/content/manuals/en/FGWPEF-102/FGWPEF-102-EN-A-v2.1.pdf

Kla3mus commented 5 years ago

Awesome, you are quick on the trigger! :) 👍

Thanks for the documentation =)

I believe that concludes this issue 👍

Kla3mus commented 5 years ago

A bit quick on the trigger there on my side... The color ring still does not work.. it does not throw exceptions or anything, but I can't get the ring to light up.

I run the following:

await wallPlug.SetLedRingColorOn(WallPlug.LedRingColorOn.PowerLoadContinuously);
var blah3 = await wallPlug.GetLedRingColorOn();
await wallPlug.SetLedRingColorOn(WallPlug.LedRingColorOn.Blue);
blah3 = await wallPlug.GetLedRingColorOn();
await wallPlug.SetLedRingColorOn(WallPlug.LedRingColorOn.Off);
blah3 = await wallPlug.GetLedRingColorOn();
await wallPlug.SetLedRingColorOn(WallPlug.LedRingColorOn.PowerLoadStep);
blah3 = await wallPlug.GetLedRingColorOn();
await wallPlug.SetLedRingColorOn(WallPlug.LedRingColorOn.Green);

And value for blah3 changes, so in some way I expect the entity to understand that we have updated the color scheme. Still there is no light.

If i turn the switch on, it lights up blue, and fades out.

Another thing is i have still not understood the event handlers.

Do you have an email or other way i can contact you? :)

roblans commented 5 years ago

Unfortunately I can't test and reproduce this issue because my WallPlug has firmware 2. Controlling the Led color is done by the Configuration Command Class. It's well documented in the manual:

https://manuals.fibaro.com/content/manuals/en/FGWPEF-102/FGWPEF-102-EN-A-v2.1.pdf On page 17 there is a section: COLOUR SETTINGS

So suppose you want to set the Led Ring Color On to RED:

parameter = 41 value = 4 (Red) size = 1 (byte)

So this becomes: await node.GetCommandClass<Configuration>().Set(41, 4, 1);

Could you please test this for me?

The SwitchedOn en SwitchedOff eventhandlers are triggered by the hardware switch (on/off) on the WallPlug

The EnergyConsumptionMeasured and PowerLoadMeasured events are triggered periodically. You can set the interval with: SetMeasureInterval(TimeSpan value)

You can also set a delta percentage for which a PowerLoadMeasured event should occur: SetPowerLoadChangeReporting(sbyte percentage)

You can contact me at: r.lans@upcmail.nl

Rob.

Kla3mus commented 5 years ago

I found that the Enums are defined in the wrong manner for this firmware version. Because of difference in the Enums, i'm creating a new class WallPlug_V3 and removing the firmware implementation you did. I'm going to test it and will send a pull req if it works as intended.

If you prefer a different approach, just let me know and we'll figure something out :) Sounds good?

roblans commented 5 years ago

OK, sounds good.

Kla3mus commented 5 years ago

Did you see the checkin'? :)

roblans commented 5 years ago

Yes I did. Just had no time today to review it. Wil do this tomorrow.

spartantechie commented 5 years ago

Hi,

I am new to zwave programming and I saw all codes in it very useful for me Very Thanks for that.I have Confusion regarding your discussion 1.Is it possible to get whether node is battery powered or usb powered? 2.How to get acknowledge from node it is in responding to requests from controller?

roblans commented 5 years ago
  1. No there is no way to distinguish between battery powered or usb powered devices. If a device is usb powered then it's like a battery device that is always awake.
  2. I don't know exactly what you mean. For non-battery devices you can always send a request and you will get a response if your using a commandclass that the device supports. For battery devices you can only send request while the device is Awake (most battery device will wake-up periodically)
phanindra466 commented 5 years ago

Hi!

I have some Wallmote used in network and when i am trying to get press and hold and slideup & down i am getting responseformat exception in zwave library but i am getting result like this 05:15:46.687: Received: COMMAND_CLASS_SWITCH_MULTILEVEL.SWITCH_MULTILEVEL_START_LEVEL_CHANGE, hex data: 26 04 38 00 02 00 05:15:49.413: Received: COMMAND_CLASS_SWITCH_MULTILEVEL.SWITCH_MULTILEVEL_STOP_LEVEL_CHANGE, hex data: 26 05

1.is press hold and slideup & down of wallmote are supported in zwave4net,if possible how can i get result?

roblans commented 5 years ago

Multilevel start and stop level changes are not (yet) implemented in ZWave4Net.

phanindra466 commented 5 years ago

Is there any alternatives that i can try for press and hold?

roblans commented 5 years ago

I've implemented both functions on the SwitchMultiLevel class

public Task StartLevelChange(bool increase, byte duration)
public Task StopLevelChange()
phanindra466 commented 5 years ago

Thanks for implementing functions.

if I used functions like this

await switch.StartLevelChange(true, 5);

1.How this handle when i press and hold wallmote?

roblans commented 5 years ago

OK, I understand now that you want to be informed when the button on the wallmote is pressed and hold. To do this you have to subcribe to the SwitchMultiLevel Changed event. Because the wallmote has 4 buttons (ZWave Endpoints), you must use the MultiChannel commandclass first to get the correct endpoint for a switch.

Try this:

            // get the MultiChannel commandclass (the wallmote has 4 endpoints)
            var multiChannel = node.GetCommandClass<MultiChannel>();

            // iterate through all endpoints 
            for (byte n = 1; n <= 4; n++)
            {
                // get the SwitchMultiLevel for the endpoint
                var switchMultiLevel = multiChannel.GetEndPointCommandClass<SwitchMultiLevel>(n);

                // end subscribe to the changed event
                switchMultiLevel.Changed += (s, e) => Console.WriteLine($"Switch {n}: {e.Report.Value}");
            }

            Console.ReadLine();    
phanindra466 commented 5 years ago

I had tried it but it is throwing exception in zwave

Exception thrown: 'ZWave.Channel.Protocol.ReponseFormatException' in ZWave.dll

roblans commented 5 years ago

Hmm, this is a hard one to find. I need some low level logging to solve this. Please add the following line to the controller:

            var controller = new ZWaveController(portName);
            // redirect logging to console
            controller.Channel.Log = Console.Out;

Run the console application, press and hold a button on the wallmote and post the outcome.

phanindra466 commented 5 years ago
2018-11-21 10:11:28.041 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:FA-02-04]
2018-11-21 10:11:28.048 Transmitted: ACK
2018-11-21 10:11:28.050 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:FB-02-04]
2018-11-21 10:11:28.051 Transmitted: ACK
2018-11-21 10:11:28.065 Transmitted: SOF Request DiscoveryNodes Payload:
2018-11-21 10:11:28.066 Received: ACK
2018-11-21 10:11:28.128 Received: SOF Response DiscoveryNodes Payload:05-00-1D-07-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-05-00
2018-11-21 10:11:28.129 Transmitted: ACK
2018-11-21 10:11:28.220 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:FC-02-04]
2018-11-21 10:11:28.220 Transmitted: ACK
2018-11-21 10:11:28.418 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:FD-02-04]
2018-11-21 10:11:28.419 Transmitted: ACK
2018-11-21 10:11:28.618 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:FE-02-04]
2018-11-21 10:11:28.619 Transmitted: ACK
2018-11-21 10:11:28.817 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:FF-02-04]
2018-11-21 10:11:28.818 Transmitted: ACK
2018-11-21 10:11:29.019 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:00-02-04]
2018-11-21 10:11:29.019 Transmitted: ACK
2018-11-21 10:11:29.219 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:01-02-04]
2018-11-21 10:11:29.219 Transmitted: ACK
2018-11-21 10:11:29.418 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:02-02-04]
2018-11-21 10:11:29.419 Transmitted: ACK
2018-11-21 10:11:29.618 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:03-02-04]
2018-11-21 10:11:29.618 Transmitted: ACK
2018-11-21 10:11:29.813 Received: SOF Response ApplicationCommandHandler TypeSingle, NodeID:002, Command:[Class:CentralScene, Command:3, Payload:04-01-04]
2018-11-21 10:11:29.814 Transmitted: ACK

This is outcome when I pressed and hold wallmote.

roblans commented 5 years ago

OK, I get it now. I was expecting that the wallmote would use the SwitchMultiLevel commandclass to send notifications. But it seems to use the CentralScene commandclass. I've implemented this class and this should work:

            var centralScene = node.GetCommandClass<CentralScene>();
            centralScene.Changed += (s, e) => Console.WriteLine(e.Report);

NuGet package: 1.0.0.182

phanindra466 commented 5 years ago

I am already using centralscene for tap(click) event on wallmote.it is giving scene value perfectly when i pressed

1.if same class is used for tap and pressed hold,How can we differentiate whether tap and pressed hold event occur?

roblans commented 5 years ago

It is passed on the KeyState property of the EventArgs:

var keyState = e.Report.KeyState

phanindra466 commented 5 years ago

I din't found any e.report.Keystate in event handler.it has only e.report.scene in EventArgs

roblans commented 5 years ago

Use the latest sourcecode of Zwave4net, or update to NuGet package: 1.0.0.182

phanindra466 commented 5 years ago

Thanks a lot, you Made By day

phanindra466 commented 5 years ago

It is working Well Thanks

roblans commented 5 years ago

You're welcome.

Rob