Author Topic: Will Pluto listen to X10 commands?  (Read 18175 times)

archived

  • Hello, I'm new here
  • Posts: 0
    • View Profile
Will Pluto listen to X10 commands?
« Reply #45 on: October 30, 2005, 10:14:00 am »
>Could CM11A or other usb/serial devices run off an MD or GC100?

Yes, when you add the cm11a, choose the MD instead of the Core as the controlled via.  For an interface, 'Controlled Via' is whatever pc you want to run the software at--then choose the correct com port from the pull-down.  It automatically shows all com ports on that pc.  Note that the gc100's com ports show up as though they're on the core.  you'll see com ports with the gc100's device number_port number.  FYI, some serial devices don't work well when attached to a gc100 since some aspects of serial com aren't implemented.  But I believe the cm11a works fine.

> Maybe if we had an X-10 category...

That would defeat the purpose of making all devices interchangeable and platform neutral.  Then instead of adding a 'light switch' you would have to add a 'Lutron light switch', and a 'x10 light switch', and a 'Vantage light switch', and you would introduce a lot of possible errors if the user didn't choose the right type for their interface.  The way it works is *any* device can be controlled via a cm11a.  Normally by convention all 'environment' devices (environment/lighting, climate, security, etc.) are controlled by a device within the 'interface' category.  All environment devices should have a device data "Port/Channel Number" (ie #12).  We have standardized that this is the data parameter where you put in the ID that the interface device will use to identify you.  So, if you add a 'light switch' and make it controlled via a cm11a, put in this field the house code: B5.  If it's controlled via EIB, put in the EIB code: 1/5/2.  If it's controlled via a gc100, put in the gc100's module/relay, like: 5:3.

All interface devices (cm11a,eib,gc100) will scan their children and see what 'Port/Channel Number' they have, and implement the commands 'on' and 'off', and if the device supports levels, the 'set level' command.

I know our approach is quite different than the others, but look at a real world example:

Right now a totally novice end-user with no computer skills can add a new device category: environment/household appliances.  And add a new device template: coffee maker.  In his house maybe he has X10, a few gc100's, an EIB system and a Lutron system.  Every one of those devices supports basic on/off relays.  Right now, even though no programmer ever wrote code for a 'coffee maker', the end user can pick any of those interfaces as his controlled via, put in the port/channel number, and his coffee maker will work.  He can control it with a scenario, or with a floorplan.

We just did an installation in a high-end home cinema which has motorized velvet drapes and black felt borders to frame the screen.  Each of the 4 felt borders and the drapes works by 'setting a level', just like with a light.  0% is the outermost position, 100% is the innermost position.  ie: top border at 20%, bottom border at 15%, drapes at 30% correctly frames a 16:9 movie.  Without touching a line of code, the installer just added a new device template for 'motorized screen borders', added 4 of them, put the controlled via as eib, and within 10 minutes had scenarios for '16:9 DVD movie', '35mm film', 'HDTV', etc. that correctly framed the screen.  Of course when the EIB interface device gets a 'set level' command to a 'screen border' device it doesn't know what a 'screen border' is.  However it sees that it has a device data 'port/channel number' and that it contains a valid EIB address, so it uses it.

If we created a specific category for 'x10 devices' and hardcoded that the cm11a only worked with certain devices, then you would lose that flexibility.  There would an 'x10 coffee maker' a 'gc100 coffee maker' a 'EIB coffee maker', etc.  The end-user couldn't just say 'i have a coffee maker and i want to control it with x10', he'd have to pick the correct interface and the correct corresponding coffee maker.  And if we didn't standardize that all devices which can be controlled via an interface must have a "Port/Channel Number", then you'd have to write code to specifically deal with a coffee maker device (and the thousands of others).

This is the code in cm11a.  Note the framework automatically passes any messages your device receives destined to a child device to the member function: ReceivedCommandForChild.  In other words, if you have a cm11a which has a child device #123 'coffee maker', then when someone sends an 'on' command to the coffee maker, the framework will call ReceivedCommandForChild:

The code looks like this:  Note the function ReceivedCommandForChild is automatically generated by the class builder DCEGen--the programmer only needs to implement inside the function.

void CM11A::ReceivedCommandForChild(DeviceData_Impl *pDeviceData_Impl,string &sCMD_Result,Message *pMessage)
{
   g_pPlutoLogger->Write(LV_STATUS, "Command %d received for child.", pMessage->m_dwID);

   string sChannel = pDeviceData_Impl->mapParameters_Find(DEVICEDATA_PortChannel_Number_CONST);

   g_pPlutoLogger->Write(LV_STATUS, "Child device %d has channel %s.", pMessage->m_dwPK_Device_To, sChannel.c_str());
   
   switch(pMessage->m_dwID) {
      case COMMAND_Generic_On_CONST:
 (send on)
         break;
      case COMMAND_Generic_Off_CONST:
 (send off)
         break;
      case COMMAND_Set_Level_CONST:
......

archived

  • Hello, I'm new here
  • Posts: 0
    • View Profile
x10
« Reply #46 on: October 30, 2005, 10:25:24 pm »
I don't think I explained myself very well about having another category for X-10. I wasn't suggesting making X-10 templates different from the other devices. I was hoping to add a navagation aid to help making X-10 standout and be together as a group. Maybe add a manufacturing group for X-10 and list all the templates/devices that are supported there. Part of the issue for people who are used to X-10 is trying to figure out how to do things the way they are used to. Finding the X-10 compatible devices among the multitude of all the supported devices is a challange.

I appreciate the niceness of device abstraction. It makes things easy until you want something specific from the underlying protocol. For example X-10 supports stacking commands and the use All Lights On/Off for a given house code. Stacking works like stating mutiple addresses followed by one function as in, A1, A2, A3, A ON. This gets the devices with the first three addresses to pay attention for the function which is to turn on. This saves time on the powerline which is really slow. All Lights On/Off is a function that takes a house code. All Lights Off A will have all the devices on house code A turn off if they are a light switch type device.

These are optimizations that we can add later but understanding the design points helps us figure it out. For now we want to be able to turn on and off devices and if something else turns on or off the device, we want pluto's state to reflect that as well.

Thanks for the code example. It looks like this is the code that handles the incoming DCE message (from the CM11A perspective). So if the user or other event wants to send an X-10 command, it uses this path to do so.

What I am trying to understand is the other direction. When the CM11A sees an incoming X-10 command to turn on the device at A1, how do we determine if A1 is a child of the CM11A and to update its state to on?

In this way incoming X-10 commands can trigger other things inside pluto, including other X-10 devices. I have modified the CM11A to receive the X-10 commands. I just need to know how to pass them up to the router.

archived

  • Hello, I'm new here
  • Posts: 0
    • View Profile
x10
« Reply #47 on: October 31, 2005, 06:34:02 am »
I figured out a few more things about C++ maps and dynamic data structures. Apparently the child devices of the CM11A dim/on/off states are maintained by the CM11A process and weren't being initialized at process startup. I was expecting something more complicated using mysql. Thanks for pointing me to the ReceivedCommandForChild method as it helped clear up some of the cobwebs. So DCE events received by CM11A for its children will update the local device state (on/off/dim) and now incoming X-10 commands will also update the same device state (but only for devices that are in the CM11A's list).

So how do we propagate the incoming X-10 status into the rest of the system so other events are triggered?

I did try playing with events to see if I could get the setting of one X-10 device to trigger another one using the events wizard but I couldn't get it to work. I tried using it via scenerios and the send command from the device page.

archived

  • Hello, I'm new here
  • Posts: 0
    • View Profile
Will Pluto listen to X10 commands?
« Reply #48 on: October 31, 2005, 08:32:44 am »
FYI, it seems there was a bug in the .31 that the child devices data parameters weren't populated correctly.  That was fixed, and the new code snippet I gave you will be included in .32.  Also, I just talked to dan.t and he will try to wrap up integrating all cm11a issues this week so we get a 100% functional cm11a in the .32 release.

> So how do we propagate the incoming X-10 status

It seems the current cm11a doesn't do this (ie doesn't yet address incoming status changes).  However this is implemented in a lot of other devices.  To do this you need to create a separate thread that will fire the events.  The main thread is created automatically by the DCE framework, and is woken up to call the appropriate functions for handling incoming messages: ie ReceivedCommandForChild, or one of the CMD_ functions for commands sent directly to your device.  The rest of the time that thread is blocked on a select() waiting for incoming messages.  NOTE: DCE connects to the router twice, 1 socket is for incoming messages, the other for outgoing.  See newbielink:http://plutohome.com/support/right.php?section=documents/documentDisplay&docID=286 [nonactive] for a tutorial showing how messages work.

Normally in such cases you would create something like a map<string,DeviceData_Impl *> m_mapX10HouseCodes which will map X10 house codes back to devices.  You don't need this for sending x10 commands--in such cases you already get a pointer to the device in 'ReceivedCommandForChild' and that has the x10 house code.  But for the reverse, when you get a state change from x10 you will want a fast way to find out what device corresponds to a house code without having to iterate through all your child devices each time looking for it.  So in the GetConfig() function, which is called automatically when the device starts up and is where you should put initialization functions, you would put an iterator that goes through all child devices, gets the house code, and stores this in that map for a reverse lookup.

So you need another thread that, depending on how the cm11a works, will either poll it for incoming events, or will block waiting for incoming data on a serial port/socket, etc.  When you get incoming data and have an event you want to fire, lookup the device with that house code as explained above, and send an event message *From* that device.  You can create a message and send it to the router:

Message *pMessage_Event = new Message(PK_Device_X10,DEVICEID_EVENTMANAGER,PRIORITY_NORMAL,MESSAGETYPE_EVENT,EVENT_New_PNP_Device_Detected_CONST,
1,EVENTPARAMETER_PK_Device_CONST,StringUtils::itos(PK_Device).c_str());
QueueMessageToRouter(pMessage_Event);

The above sends a message of type event, with the event id "New PNP device detected", and 1 parameter "PK_Device".  Note that for a message of type event, the id is the primary key in the pluto_main table Event, and for command the table Command.  If it's an event, the parameters are from table EventParameter, if it's a command, from table CommandParameter.  The sql2cpp utility automatically creates header files that have #define's with all the constants.  So whenever you see a [TABLE_NAME]_[Description]_CONST, like EVENTPARAMETER_PK_Device_CONST, that is defined the file: #include "pluto_main/Define_EventParameter.h"

Also, DCE automatically creates helper functions to automatically form commands and events.  If you have a compiler with auto-complete (I use VisualStudio.net), type DCE:: and then it will give you a list of all the commands pluto knows, and auto-complete will automatically give you a constructor that takes all the command parameters, telling you the names and types.  Use 'SendCommand' to send a command created this way, like this:

DCE::CMD_Set_Text CMD_Set_Text(m_dwPK_Device,pMessage->m_dwPK_Device_From,"",pLastApplication->m_sName,TEXT_STATUS_CONST);
SendCommand(CMD_Set_Text);

DCEGen also automatically creates helper functions to send events.  In the device template for your device add whatever events your device will fire.  Then when you re-run DCEGen, it will add member functions to your base classe to automatically fire events, like so:

//<-dceag-h-b->
   /*
            AUTO-GENERATED SECTION
            Do not change the declarations
   */
....
         *****DATA***** accessors inherited from base class
   string DATA_Get_Path();
   int DATA_Get_PK_Users();

....

         *****EVENT***** accessors inherited from base class
   void EVENT_Touch_or_click(int iX_Position,int iY_Position);
...

So if you want to fire a sensor triggered event, you can either create the message manually (ie new Message( ...  EVENT_Sensor_Triggered_CONST )...) and send it with QueueMessageToRouter, or in the device template page in the pluto admin site add the 'sensor triggered' event, and then call the helper function to automatically create the event message and send it:
EVENT_Sensor_Triggered();  Using the pre-built event functions sends the events from yourself (ie cm11a) so for devices like this where you send the events from another device (ie your child sensor) you will send the message using QueueMessageToRouter so you can specify the from device.

With that being done, your device will send events.  There are 2 ways these events can be processed.  Firstly, another device may intercept them.  Security_Plugin is responsible for all the logic of implementing a home security system.  Note this:
bool Security_Plugin::Register()
....
    RegisterMsgInterceptor((MessageInterceptorFn)(&Security_Plugin::SensorTrippedEvent) ,0,0,0,0,MESSAGETYPE_EVENT,EVENT_Sensor_Tripped_CONST);

That means any time anybody sends a sensor tripped event, the member function SensorTrippedEvent() event will be called and passed a copy of the message.  Security_Plugin has all the logic of determining whether the sensor that fired the event is part of the alarm system, whether the sensor is active/bypassed, and when it's time to sound the alarm.  That plain text dce link above also includes an example of registering a message interceptor by hand using a socket.

The second way of responding to events is to create an event handler in pluto admin in wizard, events, respond to events.  Here is how an end-user says 'when x event comes in, do y'.  Pick 'Sensor is tripped' from the pull-down, choose the sensor device, and pick the commands.  Then whenever that sensor is tripped, those commands will get executed.

You could also easily add your own events: In the device template choose 'add new event' and create an event 'Coffee Ready'.  Then in your cm11a, wherever is the code that handles incoming messages, you would lookup the device that fired the event in m_mapX10HouseCodes and then check the device template.  If it's your new 'Coffee Ready' device, send the 'Coffee Ready' event instead of the general purpose 'Sensor Tripped'.  Then the user can go in pluto admin to 'respond to events' and pick 'coffee ready' and say what they want to happen in such a case.

Since the device templates are shared across all devices, this is why it may be a good idea to put that 'translation logic' in a separate c++ class that all interfaces devices share.  This class could have a 'TranslateIncomingEvent' function that does a:

if( devicetemplate==coffeemaker )
  event==coffee ready

And then all interface devices, cm11a, Lutron, gc100, etc., could call that common function and you wouldn't need to build that logic into each one.  I will talk to daniel t about doing that so one person one time adds a new 'coffe maker' device and an entry in the translation class, and then every automation interface will know what event to fire when a device 'coffee maker' changes state.

archived

  • Hello, I'm new here
  • Posts: 0
    • View Profile
x10
« Reply #49 on: October 31, 2005, 06:31:30 pm »
I left a copy of my recent changes (via svn diff) at the url I sent to dan.t. Hopefully you got them and they make sense. My latest changes parse all the X-10 protocol and prepare for sending the EXTENDED function.

The CM11A already has a thread that dequeues the incoming DCE message for the child device and sends it to the CM11A. I added code that checked for incoming data from the serial port and process it. The serial port isReadEmpty method was the one I was referring to as not having win32 support.

Currently lsof shows CM11A having three sockets to the DCERouter. They all must be created by the framework as I don't see any explicit socket opens anywhere.

Caching X-10 house/unit codes to device names makes sense. Does the CM11A get a notification message when a new child for it is created or removed?

Should we send an Event_On or Event_Off instead?

Most devices that are connected via the X-10 protocol only have on/off or off/dimmed with values from 0-100. Some of the smarter light switches have preset values or scenes. I am not sure why you would want another devicetemplate for a device that only supports on/off. Wouldn't you only want a new device template to hold local device data that is unique to that device? I can see that for the RCS X-10 thermostats where saving different temperature values in the template would translate into different X-10 commands being sent/received.

For the vast majority of X-10 transactions, 0-100 will be enough. I probably need to reread your post a few more times and play with sending some messages. What other wrappers are good examples to look at in this regard?

archived

  • Hello, I'm new here
  • Posts: 0
    • View Profile
Will Pluto listen to X10 commands?
« Reply #50 on: October 31, 2005, 07:56:16 pm »
> Currently lsof shows CM11A having three sockets to the DCERouter.

Correct, the framework does that.  It actually creates 2 outgoing sockets (you can have as many outgoing sockets as you want, and only 1 incoming).  The 2nd outgoing socket has used for other special messages.

> Does the CM11A get a notification message when a new child for it is created

No, we've had a lot of debate about this...  You get all your devices when you startup, and dcerouter also loads them at startup.  If the user adds/removes devices in pluto admin nobody is notified of this.  It is up to the user to do a 'quick reload router', which causes the router to reload (basically a clean restart), and all devices in the whole house do so also and they all get their list of children clean.  We thought about having an 'on the fly' notification, but since there are hundreds of devices written by different people, if the framework started deleting pointers to devices previously created, and the author of the module wasn't careful with his mutex's, it could cause the devices to crash.  So for simplicity, you can assume the cm11a's list of child devices is fixed and if the user wants to change them, the cm11a will be stopped and restarted by the framework.

> Should we send an Event_On or Event_Off instead?

There is a generic on/off event.  However the cm11a should do some logical translation.  For example, sensors should fire 'sensor tripped' and not on/off, because that's the event security plugin looks for.

> I am not sure why you would want another devicetemplate for a device that only supports on/off.

It's not required.  We have a device template 'generic i/o' that's a catch all.  (going back to my coffee maker example) If you add a 'coffee maker' you don't need to add a new device template.  You could use 'generic i/o' or even 'light switch' for that matter.  The reason for creating one is just to make it easier for the user.  A 'coffee maker' device template can have a default floorplan icon of a 'coffee maker', and it's easier for the user to keep track of what's what that way.  Plus it allows other interface devices that maybe do something more special to add more functionality.  While x10 may only support on/off, maybe Lutron has a specific command for turning the coffee maker on that takes as a parameter the user who turned it on so it can use his brew settings.  By having a specific device template 'coffee maker' instead of everybody using a 'generic i/o', it allows for future expansion.

> For the vast majority of X-10 transactions, 0-100

The Set level command is defined as taking a parameter between 0-100.  So if the user wants the light at 50%, you will always get a set level of 50.  Some devices use 0-255.  So that interface device is expected to multiply/divide by 2.55.  This ensures that all interfaces across the board are compatible and a 'set level 50' will do the same thing on all lights.

> What other wrappers are good examples to look at in this regard?

I know we use the EIB for automation a lot.  I didn't write it though.  I did write Tira and IRTrans which aren't automation per se, but in both cases the respond to Pluto commands and in turn send commands to the devices, and in both cases they wait for incoming events and in turn fire pluto events and commands.