Interfacing the X10 SDK with Borland C++ 6 is problematic (to put it nicely) due to the way Variants are handled between the DLLs and BCB6.
Following is a workaround that bypasses the Variants issue, allows send and receive and doesn't require an external executable (i.e. ahcmd.exe). This process uses an embedded VBScript to process sends and receive via an event callback(/sink)
To avoid any problems interfacing BCB6 to the ActiveHome DLLs, we'll avoid the use of Variants entirely.
To accomplish this, we'll use the X10Inteface ActiveX component and the Microsoft Script Control component and the ahscript.dll via VBScript automation.
All are available free of charge from X10 and Microsoft.
Install the ActiveHome SDK.
Add the three components to your component palette:
ActiveHomeScript:
File->Close All
Component->Import ActiveX Control
Select ActiveHomeScript and click Install.
Select Into New Package and create a new package for the control.
Answer Yes to any prompts.
File->Save All
File->Close All
X10 Controls:
Component->Import ActiveX Control
Select X10 Controls and click Install.
Select Into New Package and create a new package for the control.
Answer Yes to any prompts.
File->Save All
Double-click the X10_OCX.cpp file in the package display to open it in the editor.
Right click the tab and select Open Source/Header File
Search for the following code:
// Definition of closures to allow VCL handlers to catch OCX events.
// *********************************************************************//
typedef void __fastcall (__closure * TX10InterfaceX10Command)(System::TObject * Sender,
BSTR bszCommand,
X10_tlb::EX10Command eCommand,
long lAddress,
X10_tlb::EX10Key EKeyState,
long lSequence,
X10_tlb::EX10Comm eCommandType,
VARIANT varTimestamp);
Make sure you are modifying the TX10InterfaceX10Command (not the TX10ControlX10Command)
Change the last parameter of this function to TDateTime as shown:
// Definition of closures to allow VCL handlers to catch OCX events.
// *********************************************************************//
typedef void __fastcall (__closure * TX10InterfaceX10Command)(System::TObject * Sender,
WideString bszCommand,
X10_tlb::EX10Command eCommand,
long lAddress,
X10_tlb::EX10Key EKeyState,
long lSequence,
X10_tlb::EX10Comm eCommandType,
TDateTime varTimestamp);
File->Save
Project->Build x10ctrls
File->Close All
This changes the component prototype so that it creates a premodified prototype when you attach the event thru the IDE.
If you reimport the ActiveX control, this change will be lost and you will have to redo it.
Microsoft Script Control:
Component->Import ActiveX Control
Select Microsoft Script Control and click Install.
If Microsoft Script Control is not listed, you need to install it. Search for sct10en.exe or Windows Script Control at microsoft.com
Select Into New Package and create a new package for the control.
Answer Yes to any prompts.
File->Save All
Start a new project (application)
Drop an X10Interface component and a ScriptControl component onto your form. (from the ActiveX tab of the component palette)
The SDK provides the ahscript.dll, a high level wrapper/interface for the X10net.dll which is a sort of queue manager for the X10 controller.
We will use the X10net directly to receive data from x10net.dll
The Windows script control will be used to run VBScript to open the automation object without all the Variant hassles.
Select the X10Interface component and click the events tab in the Object Inspector.
Double-click OnX10Command.
Verify that the last parameter of the prototype is
TDateTime varTimestampAdd this code to the function:
void __fastcall TForm1::X10Interface1X10Command(TObject *Sender,
BSTR bszCommand, EX10Command eCommand, long lAddress,
EX10Key EKeyState, long lSequence, EX10Comm eCommandType,
TDateTime varTimestamp)
{
AnsiString house = (char)((lAddress>>4 & 0x0F) + 'A');
AnsiString unit = (lAddress & 0x0F) + 1;
AnsiString cmd = bszCommand;
ListBox1->ItemIndex = ListBox1->Items->Add(house + unit + " " + cmd);
}
Add A listbox and two buttons to the form.
Double-click the OnClick events of the two buttons and add this code:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
SendCommand(L"a1 on");
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{
SendCommand(L"a1 off");
}Add this function:
//---------------------------------------------------------------------------
void __fastcall TForm1::SendCommand(WideString cmd)
{
WideString code;
code = "Sub SendData\n" \
"On Error Resume Next\n" \
"Set AH = CreateObject(\"X10.ActiveHome\")\n"
"Call AH.SendAction(\"sendplc\", \"" + cmd + "\")\n" \
"End Sub";
ScriptControl1->Reset();
ScriptControl1->Language = L"VBScript";
ScriptControl1->AddCode(code);
ScriptControl1->ExecuteStatement(L"SendData");
ScriptControl1->Reset();
}
SendCommand() sets up a ScriptControl with a VBScript subroutine and then executes it. The VBScript attaches to the ActiveHome (ahscript.dll) and sends the command.
Add this prototype to the form header file Form1 _published section:
void __fastcall SendCommand(WideString cmd);
Compile and run.
Using an external controller, turn on A1. You should receive at least two events for each selection. The first is a KEYON event, indicating when the the key was pressed. Next is a KEYOFF event indicating that the key was released. Both events will have the same address and command (0 Off). If you hold down the key, you get more events. The sequence value increments as long as the same key is being pressed/released. This can be used to determine when a sequence is over depending on your need. See the Type Library code for an explanation of values for the various fields passed on the receive event.
Receiving is automatic and is handled by the X10Interface1X10Command callback function
Sending is as simple as SendCommand(L"a1 off")
You can also implement sendrf, though this code hardcodes to sendplc in the VBScript.
-----
Alan Capesius
Tech World, Inc
Makers of the XVideo10 and RSVSwitch home automation video controllers.
http://www.tech-world.comall comments to the forum please.