FluentDwelling Support
FluentDwelling?
If you don’t know what FluentDwelling is, please go to the project page.
Getting Started – Requirements
To use FluentDwelling, you’ll need some kind of development environment for writing .NET 4 applications. By default, that’s Visual Studio 2010. Microsoft offers some free express editions (either Visual C# 2010 Express or Visual Basic 2010 Express should work well). If you want to make changes to the library, you’ll also want to be able to run the unit tests that come with it, and for that you’ll need NUnit. You don’t need NUnit just to use the library in your own application.
You’ll also need to get a 2413U:
… and you’ll need to hook it up to your computer with a USB cable, and install the virtual com port (VCP) driver from FTDI. When you install the driver, it should detect the 2413U and create a new COM port on your PC for it (it will show up in your device manager):
That’s the bare minimum to use FluentDwelling, but you can’t do much with it (well, you could flash the LED on the 2413U, and respond to the SET button being pressed, but we think that’s still pretty lame). Lighting Controls are the typical choice to get started:
Reference the FluentDwelling Assembly (DLL)
We have to assume you’re familiar with writing .NET applications with Visual Studio, but if not, here’s a great introductory tutorial that prints “Hello World!”.
You’ll also need to know how to reference the FluentDwelling DLL from your program. Once you’ve created a project in Visual Studio, under the project you’ll see a folder called References. Right click on that and choose Add Reference. Then go to the Browse tab, and navigate to the folder where you’ve unzipped the download package from the FluentDwelling product page. The .dll file will be in this subdirectory:
FluentDwelling.2011.09.17\trunk\SoapBox.FluentDwelling\bin\Release
The file will be called SoapBox.FluentDwelling.dll
Try Communicating with the 2413U
Assuming you’ve got this far, you should have the 2413U plugged into your PC with a USB cable, and plugged into the wall. Let’s see if we can control the LED. In your program, type this:
var plm = new Plm("COM4"); // replace COM4 with the VCP port that was installed plm.Led .EnableManualControl() .TurnOn();
If the word “Plm” is underlined with swigglies, you probably need to put the following line at the top of your program file:
using SoapBox.FluentDwelling;
That prevents you from having to preface every identifier with SoapBox.FluentDwelling.
Now if you run your program, the LED should turn on. It may not be as bright as you expect, and before you enabled manual control, it was probably kind of blinking anyway, so it might be hard to tell. Try this and see if it turns off:
var plm = new Plm("COM4"); plm.Led .EnableManualControl() .TurnOff();
Now it should be off. If it is, it’s working! If not, check your COM port address, and check your cabling.
Getting the 2413U Device Information
While it’s not that exciting, you can grab the device information from the 2413U, like this:
var info = plm.GetInfo(); MessageBox.Show( "Device Category: " + info.DeviceCategory + "Subcategory: " + info.DeviceSubcategory + "Firmware: " + info.FirmwareVersion.ToString());
The device category should be “Network Bridges”, and the subcategory would be “PowerLinc – USB (Dual Band) [2413U]”.
Call Receive()
If you want to receive messages from the 2413U, you need to setup some mechanism to call .Receive() at regular intervals. If you’re in a console application, you could do this:
while(true) { plm.Receive(); System.Threading.Thread.Sleep(100); // wait 100 ms }
…but it’s more likely you’re using a WinForms or WPF application. If you’re using WPF, put this in your Form.Loaded event:
// Setup a timer on the GUI thread to call the Receive loop var timer = new DispatcherTimer(); timer.Interval = new TimeSpan(0, 0, 0, 0, 100); // milliseconds timer.Tick += new EventHandler((s, args) => { plm.Receive(); }); timer.Start();
If you’re using WinForms, then use a Windows Forms Timer.
Once you’ve done that (actually, preferrably before you start the timer), you can hook into various events, like the SET button tapped:
plm.SetButton.Tapped += new EventHandler((s, e) => { MessageBox.Show("PLM SET Button Tapped."); });
Here are some other events that can be raised related to the SET button:
- plm.SetButton.PressedAndHeld
- plm.SetButton.ReleasedAfterHolding
- plm.SetButton.UserReset (SET Button Held During Power-up)
Working with the All-Link Database
The 2413U maintains a list of all devices it has been “paired” with. You pair a device to it by holding down the SET button on the 2413U until it beeps, and then holding down the SET button on the other device, and waiting for it to beep (they both have to be plugged in and able to communicate with each other for this to work).
To get a list of all devices in the All-Link Database, do this:
var database = plm.GetAllLinkDatabase();
You can then iterate over the result with a foreach statement:
foreach (var record in database.Records) { var deviceId = record.DeviceId; }
The only particularly useful thing the record gives you is the “device ID” of each device in the database. The device ID is a unique address that each Insteon-compatible device has built into it when it leaves the factory. It looks something like this: “12.34.56”. Devices need to know each others’ IDs in order to send messages to each other. For our purposes, we need the device ID in order to call the TryConnectToDevice method. We can use the device IDs returns from the database, or we can hard code them, like this: “12.34.56”. This is possible because each device has the ID written on it, so if you’re just writing some custom application for your house, you’ll know what all your device IDs are before you start.
Connect to a Lighting Control
So, assuming we want to connect to device “12.34.56” that’s been linked to our 2413U, and we know it’s a lighting control (either switched or dimmable), we can do this:
DeviceBase device; if(plm.Network.TryConnectToDevice("12.34.56", out device)) { var lightingControl= device as LightingControl; lightingControl.TurnOn(); } else { MessageBox.Show("Could not connect."); }
Now if you get squiggly lines under LightingControl, make sure you have this at the top of your program file:
using SoapBox.FluentDwelling.Devices;
Warning… if you manage to connect to device “12.34.56” and it’s not a Lighting Device, you’ll get an “object reference not set to an instance of an object” exception when you try to call lightingControl.TurnOn() because the “as” instruction returns null if “device” isn’t a lightingControl. If you’re not really sure that the device is a LightingControl, you can do this:
if(device is LightingControl) { // you're good to go }
However, if you know it’s a lighting control because you bought it and plugged it in, you’re pretty safe!
What other things can LightingControls do? Obviously if there’s a .TurnOn() method, there’s also a .TurnOff() method. Interestingly you can also try to query the device to see if it’s on or off:
byte onLevel; if(lightingControl.TryGetOnLevel(out onLevel)) { if(onLevel == 0) { MessageBox.Show("The light is off."); } else { MessageBox.Show("The light is on."); } }
So why is the “onLevel” a byte? Shouldn’t it be a “bool” because the light is either on or off? Well, the LightingControl could be a DimmableLightingControl. If that’s the case, then the onLevel could be anything from 0 to 255.
Special Capabilities of DimmableLightingControl
If you know you’ve got a DimmableLightingControl, you have some extra features. You can turn the light on to a specific level (0 to 255):
DeviceBase device; if(plm.Network.TryConnectToDevice("12.34.56", out device)) { var lightingControl= device as DimmableLightingControl; lightingControl.TurnOn((byte)128); } else { MessageBox.Show("Could not connect."); }
That will turn it on to 50%, instantly. You can use the .RampOn(…) method if you want it to turn on slowly to your desired level, instead of instantly changing. The .TurnOff() method works the same for any lighting control (turns off instantly), but you can also do a .RampOff() if you have a DimmableLightingControl. Also try these methods:
- .BrightenOneStep()
- .DimOneStep()
- .BeginBrightening()
- .BeginDimming()
- .StopBrighteningOrDimming()
IrrigationControl
If your device is an IrrigationControl, like the EZFlora:
…then you can call these methods:
- .TurnOnSprinkerValve(x) (where x is a sprinkler valve #)
- .TurnOffSprinkerValve(x)
- .TurnOnSprinklerProgram(x) (where x is a sprinkler porgram #)
- .TurnOffSprinklerProgram(x)
- .LoadInitializationValues()
- .LoadEepromFromRam()
- .LoadRamFromEeprom()
- .InhibitCommandAcceptance()
- .ResumeCommandAcceptance()
- .SkipForward()
- .SkipBack()
- .EnablePumpOnV8() (we think it enables a pump at valve 8?)
- .DisablePumpOnV8()
- .EnableDeviceStatusChangedBroadcast()
- .DisableDeviceStatusChangedBroadcast()
- .EnableSensorReading()
- .DisableSensorReading()
- .DiagnosticsOn()
- .DiagnosticsOff()
You can also read the valve status:
byte valveStatus; if(irrigationControl.TryGetValveStatus(out valveStatus)) { // do something with valve status }
We’re pretty sure the valve status is just interpreted as on/off values, one bit in the byte for each valve.
PoolAndSpaControl
If your device is a PoolAndSpaControl, you can call these methods:
- .TurnOnDevice(PoolAndSpaDevice.Pool) (replace Pool with Spa, Heat, or Pump)
- .TurnOffDevice(PoolAndSpaDevice.Pool) (same)
- .TurnOffDevice(PoolAndSpaDevice.All) (special command to turn off all)
- .TurnOnDevice(8) (turns on by number)
- .TurnOffDevice(8)
- .RaiseTemperatureSettingBy(x)
- .LowerTemperatureSettingBy(x)
- .LoadInitializationValues()
- .LoadEepromFromRam()
You can also read the thermostat mode, water & ambient temperatures, and pH (assuming your device supports it):
PoolAndSpaThermostatMode thermostatMode; if(poolAndSpaDevice.TryGetThermostatMode(out thermostatMode)) { MessageBox.Show("Thermostat mode: " + thermostatMode.ToString()); } byte ambientTemperature; if(poolAndSpaDevice.TryGetAmbientTemperature(out ambientTemperature)) { // use temperature } byte waterTemperature; if(poolAndSpaDevice.TryGetWaterTemperature(out waterTemperature)) { // use temperature } byte pH; if(poolAndSpaDevice.TryGetPH(out pH)) { // use pH value }
SensorsActuators
There is a special category of devices called SensorsActuators:
These are more low-level devices, designed to interface directly with dry contact switches, environmental sensors, etc. One even includes the ability to detect when you turn on a specific audio/video device, so you could make your lights dim. You can manipulate discrete outputs with these methods:
- .TurnOnOutput(x) (where x is the output number)
- .TurnOffOutput(x)
- .WriteByteToOutputPort(0xAF)
The last method writes 8 output bits at a time. You can read the input port all at once (8 bits):
byte inputBits; if(sensorsActuators.TryGetInputPort(out inputBits)) { // you'll have to decode the bits from inputBits yourself }
Some inputs are “analog” values, where you just read one value as a single reading. You can read each one similarly:
byte sensorValue; if(sensorsActuators.TryGetSensorValue(3, out sensorValue)) { // in this case, 3 is the analog input address }
Note that version 2013.07.09 of FluentDwelling adds 4 new methods specifically tested for operating the I/O Linc 2450 relay and sensor:
- .TurnOnRelay()
- .TurnOffRelay()
- .TryGetRelayStatus(…)
- .TryGetSensorStatus(…)
The first 2 control the relay output, the third reads back the current state of the relay (0 = off, 255 = on), and the fourth reads the current state of the sensor (0 = open, 1 = closed).
WindowCoveringControl
If your device is a WindowCoveringControl, you can call these methods:
- .Open()
- .Close()
- .Stop()
- .Program() (we’re really not sure what this does)
- .MoveToPosition(128) (that would be half-way open)
… unfortunately we don’t know of any Insteon-compatible Window Covering controls, but if they do make one, this should work!
Error Reporting
Calling any methods on the FluentDwelling API should not throw an exception due to communication issues. To monitor the success or failure of a command, test the .Error property of the plm after your command:
if(plm.Error) { MessageBox.Show("Error: " + plm.Exception.Message); }
You can also register to be notified of an exception. This is a good way to log errors in a single place:
plm.OnError += new EventHandler((s, e) => { logError(plm.Exception.Message); });
Responding to Messages From Controllers
New in version 2011.09.17 is the ability to receive messages sent from controllers (such as KeypadLinc, SwitchLinc, or motion detectors) that are sent to the PLM.
You can link these controllers to the PLM the same way you would link the controller to an outlet or other LightingControl. First you hold down the set or scene button on the controller to put it into linking mode, and then you hold down the SET button on the PLM until it beeps. The PLM is now setup to receive messages from the controller as if it were a lighting device. Of course it can’t do anything about it because it doesn’t contain any switches, etc., so it just passes the message along to the computer.
To receive this message in your C# program, you need to handle the following event:
plm.Network.StandardMessageReceived += new StandardMessageReceivedHandler((s, e) => { MessageBox("Message received: " + e.Description + ", from " + e.PeerId.ToString()); });
Pay particular attention to the PeerId, Group, Command1, and Command2 properties. PeerId tells you what controller sent the message, Group tells you what scene (so which button was pressed), and the Command1 & 2 properties tell you what command it is (0x11 is “Turn On” and 0x13 is “Turn Off”, for instance).
Further Support
If you have more questions, please email scott@soapboxautomation.com. I’ll try to get back to you as quickly as possible.
Contributions
If you’ve made an improvement to FluentDwelling and you’d like to contribute it back to our project, we’d really appreciate that! If it’s just a short/quick bug-fix, then please just email it to contributions@soapboxautomation.com. If it’s more substantial (approximately 8 lines or more), then we will require a signed contributor’s agreement. Again, please email the contributions address, and we can get you setup.