OnTrue
Program.Setup(()=>{
Program.AddInputField("HubAddress", "192.168.0.?", "Insteon Hub IP Address");
Program.AddInputField("HubUsername","admin", "Insteon Hub Username");
Program.AddInputField("HubPassword","?", "Insteon Hub Password");
Program.AddInputField("HubPort", "25105", "Insteon Hub Port");
//
// Create 5 virtual modules with the domain "InsteonHub" and with address from 1 to 5
// "Light" is the type and "Generic/Light" is the widget to be used to display the virtual module.
// These are for non-dimmable Lights.
Program.AddVirtualModules("InsteonHub", "Light", "homegenie/generic/light", 1, 5);
// Add the InsteonID Parameter.
Program.AddFeature( "InsteonHub", "Light", "InsteonID", "Insteon ID (e.g. AA.BB.CC) or X10 ID (e.g. J12).", "text");
});
return true;
// Sanity testing of the HubAddres and Password. Also, the Hub port, Username need to be entered.
if (Program.InputField("HubAddress").Value == "" || Program.InputField("HubAddress").Value.EndsWith("?"))
{
Program.Notify("InsteonHub", "Invalid HubAddress. Please fix.");
Pause(2);
}
if (Program.InputField("HubPassword").Value == "" || Program.InputField("HubPassword").Value.EndsWith("?"))
{
Program.Notify("InsteonHub", "Invalid HubPassword. Please fix.");
Pause(2);
}
// get a list of all modules in the InsteonHub Domain
var hueModules = Modules.InDomain("InsteonHub");
string hubAddress = Program.InputField("HubAddress").Value;
string hubUsername = Program.InputField("HubUsername").Value;
string hubPassword = Program.InputField("HubPassword").Value;
string hubPort = Program.InputField("HubPort").Value;
// construct the URL that is used to communicate with Hub over Http.
string hubUrl = "http://" + hubAddress + ":" + hubPort + "/";
/// <summary>
string[] _HouseCodes =
{ // House Code A B C D E F G H I J K L M N O P
"6", "E", "2", "A", "1", "9", "5", "D", "7", "F", "3", "B", "0", "8", "4", "C"
};
// <summary>
Func<string, string> getX10HouseCode = (string c) =>
{
int index = (c.ToCharArray()[0]) - 'A';
if (index < 0 || index >= 16)
{
Program.Notify("X10 Error", "Invalid House Code detected.");
index = 0;
}
return _HouseCodes[index];
};
// <summary>
string[] _UnitCodes =
{ // Unit Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
"600", "E00", "200", "A00", "100", "900", "500", "D00", "700", "F00", "300", "B00", "000", "800", "400", "C00"
};
// <summary>
Func <string, string> getX10UnitCode = (string c) =>
{
int index = Int32.Parse(c) - 1;
if (index < 0 || index >= 16)
{
Program.Notify("X10 Error", "Invalid Unit Code detected.");
index = 0;
}
return _UnitCodes[index];
};
// Low level function for sending an Insteon or X10 command to the InsteonHub
Func<string, bool> sendHubCommand = (string cmd) =>
{
Net.WebService(hubUrl + cmd).WithCredentials(hubUsername, hubPassword).Call();
return true;
};
// Function for constructing an Insteon "DirectCommand".
Func<string, string, string, bool> SendDirectCommand = (string insteonID, string command, string level) =>
{
// Insteon Hub Direct commands take the following form:
// http://172.30.1.101:25105/3? 0262 0EA722 0F 11 FF =I=3
// HTTP Resource + Direct Command Flag + Device + SD Flag + CommandOp + Level + Unknown?
const string directFlag = "3?0262"; // Direct command flag
const string sdFlag = "0F";
const string post = "=I=3";
string cmd = directFlag + insteonID + sdFlag + command + level + post;
sendHubCommand(cmd);
return true;
};
// Function for constructing an Insteon "X10 Command".
Func<string, string, string, string, bool> SendX10Command = (string house, string unit, string cmdOp, string level) =>
{
// Insteon Hub X10 commands take the following form. Note that a sequence of two http commands are needed.
// http://172.30.1.101:25105/3? 0263 6 600 =I=3
// HTTP Resource + X10 Command Flag + House Code + Unit Code + Unknown?
// http://172.30.1.101:25105/3? 0263 6 280 =I=3
// HTTP Resource + X10 Command Flag + House Code + Command + Unknown?
const string x10flag = "3?0263"; // x10 command flag
const string post = "=I=3";
string cmd1 = x10flag + house + unit + post;
string cmd2 = x10flag + house + cmdOp + post;
// X10 is inherrently unreliable. Each command is sent multiple times to improve reliability.
const int X10_REPEAT_COUNT = 3;
for (int count = 0; count < X10_REPEAT_COUNT; count++)
{
sendHubCommand(cmd1);
Pause(1);
sendHubCommand(cmd2);
Pause(1);
}
sendHubCommand(cmd1);
Pause(1);
sendHubCommand(cmd2);
/*
Program.Notify("X10 cmd1", cmd1);
Pause(10);
Program.Notify("X10 cmd2", cmd2);
Pause(10);
*/
return true;
};
// Web service function for handling HomeGenie HTTP commands of the form:
// http://<hg_address>/api/...
When.WebServiceCallReceived("InsteonHub", ( args ) =>
{
// args will be of the form : http://<hg_address>/api/InsteonHub/<hg_module_number>/<hg_command>
// exract the lightnumber and command.
string[] reqs = ((string)args).Split('/');
//string domain = reqs[0];
string lightnumber = reqs[1];
string command = reqs[2];
string parameter = "";
var module = hueModules.WithAddress(lightnumber).Get();
if (module.HasFeature("InsteonID"))
{
string insteonID = module.Parameter("InsteonID").Value;
// The value of InsteonID will be either of dotted hex id form (e.g., "AA.BB.CC") indicating an Insteon
// device or of the house/unit form (e.g., "A1") indicating an X10 device.
bool isDottedHexId = (insteonID.IndexOf(".") > 0);
try
{
if (isDottedHexId)
{
// Insteon use hex brighness levels from 0x00 (off) to (0xFF) fully on.
const string CMD_LEVEL_FULL = "FF"; // 100% brightness
const string CMD_LEVEL_OFF = "00"; // 0% brightnes (off)
// Insteon Direct commands. A full list of other commands can be founds here
// http://www.madreporite.com/insteon/commands.htm.
const string CMD_OP_ON = "11"; // 0x11 = ON
const string CMD_OP_OFF = "13"; // 0x13 = OFF
// convert InsteonID from "dotted format" (AA.BB.CC) format to packed format (AABBCC)
string hexID = insteonID.Remove(2,1).Remove(4,1);
switch(command)
{
case "Control.On":
SendDirectCommand(hexID, CMD_OP_ON, CMD_LEVEL_FULL);
Program.RaiseEvent(module, "Status.Level", "1", "Insteon Light On");
break;
case "Control.Off":
SendDirectCommand(hexID, CMD_OP_OFF, CMD_LEVEL_OFF);
Program.RaiseEvent(module, "Status.Level", "0", "Insteon Light Off");
break;
case "Control.Toggle":
if (module.Parameter("Status.Level").DecimalValue == 0)
{
SendDirectCommand(hexID, CMD_OP_ON, CMD_LEVEL_FULL);
Program.RaiseEvent(module, "Status.Level", "1", "Insteon Light ToggleOn");
}
else
{
SendDirectCommand(hexID, CMD_OP_OFF, CMD_LEVEL_OFF);
Program.RaiseEvent(module, "Status.Level", "0", "Insteon Light ToggleOff");
}
break;
case "Control.Level":
// convert status.Level (0.0 to 1.0) to 2-digit hexadecimal Insteon level (00 to FF).
string level = ((int)(double.Parse(parameter) * 255)).ToString("X2");
SendDirectCommand(hexID, CMD_OP_ON, level);
Program.RaiseEvent(module, "Status.Level", (double.Parse(parameter) / 100D).ToString(), "Insteon Light Dim");
break;
}
}
else
{
// If InsteonID is a non-dotted foramt, we expect X10 house/unit format (e.g. J10)
// X10 commands. A full list of other commands can be founds here
// http://www.leftovercode.info/smartlinc_x10.html
const string X10_CMD_OP_ON = "280";
const string X10_CMD_OP_OFF = "380";
const string X10_CMD_OP_BRIGHT = "580";
const string X10_CMD_OP_DIM = "480";
const string X10_CMD_OP_ALL_ON = "180";
const string X10_CMD_OP_ALL_OFF = "680";
const string X10_LEVEL_IGNORE = "";
string house = insteonID.Substring(0,1); // first char is the house
string unit = insteonID.Remove(0,1); // 2nd and 3rd chars are the unit
string houseCode = getX10HouseCode(house);
string unitCode = getX10UnitCode(unit);
switch(command)
{
case "Control.On":
SendX10Command(houseCode, unitCode, X10_CMD_OP_ON, X10_LEVEL_IGNORE);
Program.RaiseEvent(module, "Status.Level", "1", "Insteon Light On");
break;
case "Control.Off":
SendX10Command(houseCode, unitCode, X10_CMD_OP_OFF, X10_LEVEL_IGNORE);
Program.RaiseEvent(module, "Status.Level", "0", "Insteon Light Off");
break;
case "Control.Toggle":
if (module.Parameter("Status.Level").DecimalValue == 0)
{
SendX10Command(houseCode, unitCode, X10_CMD_OP_ON, X10_LEVEL_IGNORE);
Program.RaiseEvent(module, "Status.Level", "1", "Insteon Light ToggleOn");
}
else
{
SendX10Command(houseCode, unitCode, X10_CMD_OP_OFF, X10_LEVEL_IGNORE);
Program.RaiseEvent(module, "Status.Level", "0", "Insteon Light ToggleOff");
}
break;
case "Control.Level":
// TODO: implement support for X10 dimming
break;
}
}
return "{ 'ResponseValue' : 'OK' }";
} catch (Exception e)
{
Program.Notify("InsteonHub ERROR!", e.Message);
Pause(2);
}
return "{ 'ResponseValue' : 'ERROR' }";
}
return "{ 'ResponseValue' : 'ERROR' }";
});
Program.GoBackground();
[]
true
text
InsteonHub
Light
InsteonID
Insteon ID (e.g. AA.BB.CC) or X10 ID (e.g. J12).
true
HomeAutomation.HomeGenie.Automation
1000
InsteonHub
Adds Insteon Hub capability to HomeGenie. The Hub provides similar capabilities to the Insteon PLM, but provides a network interface rather than serial/usb. You will need to know the Hub IP address, username, and password. You will also need to know the Insteon ID of each module you want to control. Support for X10 is not yet supported but planned.
Devices and Things
2014-12-25T03:39:47.598386Z
2015-01-03T22:11:46.989052Z
CSharp
true