See part 2 in my investigation
I recently had installed a new air conditioning system and it came with a new Lennox iComfort Thermostat that talks to the cloud over a wifi connection. After spending a little time looking at messages that get passed back and forward from chrome to the cloud service using the chrome developer tool, it looks like a fairly straight forward sort of REST api.
I managed to get some ruby code that log in, then queries the status of the the thermostat.
The authentication is a pain, since you log into the website using an ASP.NET web application, so it needs the __VIEWSTATE and the __EVENTVALIDATION form fields to be present. I have hardcoded them for the moment, but intended to pull them out of the of the response on the first page. I should set up a proxy and see if the android app uses a simpler API for authenticating.
Once authenticated you can send a JSON message like
{"hidden_gateway_SN":"XXXXXX",
"pref_temp_units":"0",
"userid":"XXXXXX",
"Central_Zoned_Away":"2",
"Cancel_Away":"-1",
"current_prg":"2",
"current_mode":"1",
"CurrentBrowser":"chrome",
"zoneNumber":"0",
"Current_Thermostat":"0",
"alertViewTypes":"0",
"alertTypes":"1",
"reminderTypes":"0"}
and you get back
{"Equipment_List"=>
[{"SystemID"=>XXXXXX,
"Friendly_Name"=>"Air Handler",
"Device_Descriptor"=>XXXXXXX,
"Control_Model_Nbr"=>"Equipment Interface Module ? AHC",
"Control_Serial_Number"=>"XXXX-xxxxxx",
"ReturnStatus"=>nil},
{"SystemID"=>XXXXXX,
"Friendly_Name"=>"Thermostat",
"Device_Descriptor"=>XXXXXX,
"Control_Model_Nbr"=>"103445-04",
"Control_Serial_Number"=>"XXXXXXXX",
"ReturnStatus"=>nil},
{"SystemID"=>72204,
"Friendly_Name"=>"Wi-Fi Controller",
"Device_Descriptor"=>XXXXXX,
"Control_Model_Nbr"=>"GS1500M",
"Control_Serial_Number"=>"Wi-XXXXXXXXX",
"ReturnStatus"=>nil}],
"AlertInfo_List"=>[],
"TStatInfo_List"=>
[{"GatewaySN"=>"XXXXXXXX",
"Zone_Number"=>0,
"Zone_Name"=>"Zone 1",
"Program_Schedule_Selection"=>0,
"Schedule_Name"=>"0|summer^1|winter^2|spring fall^3|save energy^4|custom",
"Program_Schedule_Mode"=>"0",
"Away_Mode"=>0,
"Pref_Temp_Units"=>"0",
"DateTime_Mark"=>"/Date(1404941631787)/",
"Zone_Enabled"=>1,
"System_Status"=>0,
"Indoor_Temp"=>74.0,
"Indoor_Humidity"=>40,
"Operation_Mode"=>2,
"Heat_Set_Point"=>57.0,
"Cool_Set_Point"=>74.0,
"Fan_Mode"=>2,
"Golden_Table_Updated"=>true,
"ConnectionStatus"=>"GOOD",
"Central_Zoned_Away"=>2,
"Zones_Installed"=>1,
"GMT_To_Local"=>-18000}],
"current_GatewayInfo"=>
{"SystemID"=>"XXXXX",
"Pref_Language_Nbr"=>0,
"Pref_Temp_Unit"=>"0",
"Cool_Set_Point_High_Limit"=>99.0,
"Cool_Set_Point_Low_Limit"=>60.0,
"Heat_Set_Point_High_Limit"=>90.0,
"Heat_Set_Point_Low_Limit"=>40.0,
"Heat_Cool_Dead_Band"=>3.0,
"Daylight_Savings_Time"=>1,
"ReturnStatus"=>"SUCCESS"},
"program_List"=>
{"00"=>
{"GatewaySN"=>"XXXXXXXXX",
"ScheduleNum"=>0,
"Zone_Number"=>0,
"Heat_Set_Point"=>68.0,
"Cool_Set_Point"=>78.0,
"Fan_Mode"=>0,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"01"=>
{"GatewaySN"=>"XXXXXXXX",
"ScheduleNum"=>0,
"Zone_Number"=>0,
"Heat_Set_Point"=>20,
"Cool_Set_Point"=>25.5,
"Fan_Mode"=>0,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"10"=>
{"GatewaySN"=>"XXXXXXXX",
"ScheduleNum"=>1,
"Zone_Number"=>0,
"Heat_Set_Point"=>68.0,
"Cool_Set_Point"=>78.0,
"Fan_Mode"=>0,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"11"=>
{"GatewaySN"=>"XXXXXXXXX",
"ScheduleNum"=>1,
"Zone_Number"=>0,
"Heat_Set_Point"=>20,
"Cool_Set_Point"=>25.5,
"Fan_Mode"=>0,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"20"=>
{"GatewaySN"=>"XXXXXXXX",
"ScheduleNum"=>2,
"Zone_Number"=>0,
"Heat_Set_Point"=>50.0,
"Cool_Set_Point"=>78.0,
"Fan_Mode"=>2,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"21"=>
{"GatewaySN"=>"XXXXXXXX",
"ScheduleNum"=>2,
"Zone_Number"=>0,
"Heat_Set_Point"=>10,
"Cool_Set_Point"=>25.5,
"Fan_Mode"=>2,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"30"=>
{"GatewaySN"=>"XXXXXXXX",
"ScheduleNum"=>3,
"Zone_Number"=>0,
"Heat_Set_Point"=>63.0,
"Cool_Set_Point"=>76.0,
"Fan_Mode"=>0,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"31"=>
{"GatewaySN"=>"XXXXXXXX",
"ScheduleNum"=>3,
"Zone_Number"=>0,
"Heat_Set_Point"=>17,
"Cool_Set_Point"=>24,
"Fan_Mode"=>0,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"40"=>
{"GatewaySN"=>"XXXXXXX",
"ScheduleNum"=>4,
"Zone_Number"=>0,
"Heat_Set_Point"=>67.0,
"Cool_Set_Point"=>72.0,
"Fan_Mode"=>0,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"},
"41"=>
{"GatewaySN"=>"XXXXXXX",
"ScheduleNum"=>4,
"Zone_Number"=>0,
"Heat_Set_Point"=>19,
"Cool_Set_Point"=>22,
"Fan_Mode"=>0,
"Central_Zoned_Away"=>0,
"ReturnStatus"=>"SUCCESS"}},
"CurrentAvailableZones"=>1,
"Zones_Installed"=>1,
"GatewaySN"=>"XXXXXXX",
"ZoneNumber"=>0,
"CurrentZoneName"=>"Zone 1",
"ServerUpdated"=>true,
"CurrentDate"=>"Jul-09-2014 09:33:51 PM",
"Central_Zoned_Away"=>2,
"Indoor_Temp"=>"74",
"fraction_Temp"=>"00",
"Indoor_Humidity"=>"40",
"Heat_Set_Point"=>"57",
"Cool_Set_Point"=>"74",
"Fan_Mode"=>2,
"Away_Mode"=>0,
"Operation_Mode"=>2,
"Pref_Temp_Units"=>0,
"System_Status"=>"idle",
"System_Name"=>"my icomfort system",
"ConnectionStatus"=>"GOOD",
"Program_Schedule_Selection"=>0,
"Program_Schedule_Mode"=>"0",
"manualSetting"=>
"cool only,2&heat only,1&heat or cool,3&off,0&emergency heat,4&"}
As you can see lots of useful information. Short term I am planning on collecting stats about how long it takes the system to cool and how long it is running. The cloud site only updates when there is a change event, so the actual data that will be written is fairly small. Long term I want to be able to hook it into my Home Automation system, which is currently OpenHab. Depending on how far I get I will post my ruby code online, but nothing I am doing is hard to replicate.
A request came in for the sample ruby code i wrote, I originally didn’t want to post this, since this was just something I hacked together. You will need to need to log into the icomfort website first, then use a tool like the gooogle chrome developer tools to grab the __VIEWSTATE, __EVENTVALIDATION cookie, and update ctl00$RightContent$txtUserName, ctl00$RightContent$txtPwd it, hidden_gateway_SN, userid. Again apologies in advance for my hacked together example.
require 'rest_client'
require 'json'
require 'uri'
require 'pp'
#RestClient.proxy = "https://localhost:8008"
response3 = RestClient.get 'https://www.myicomfort.com/Default.aspx'
response3.cookies
# => {"_applicatioN_session_id" => "1234"}
p response3.cookies
#p response3
@session_cookies = response3.cookies
response2 = RestClient.post(
'https://www.myicomfort.com/Default.aspx',
{
"__LASTFOCUS" => "",
"__EVENTTARGET=" => "",
"__EVENTARGUMENT=" => "",
# "__VIEWSTATE" => "",
"__VIEWSTATE" => '<REPLACE WITH YOUR VEIW STATE>',
# "__EVENTVALIDATION" => '',
"__EVENTVALIDATION" => '<REPLACE WITH YOUR EVENTVALIDATION>',
'ctl00$RightContent$hdnPwd' => "",
'ctl00$RightContent$txtUserName' => "<REPLACE WITH YOUR USERNAME>",
'ctl00$RightContent$txtPwd' => "<REPLACE WITH YOUR PASSWORD>",
'ctl00$RightContent$chkRemember' => "on",
'ctl00$RightContent$btnLogin' => "Log in"},
{:cookies => @session_cookies}
) { |response, request, result, &block|
if [301, 302, 307].include? response.code
p response.cookies
@session_cookies = response.cookies
#response.follow_redirection(request, result, &block)
response
else
p response
response.return!(request, result, &block)
end
}
#p response2.cookies
#p response2.code
p @session_cookies
my_hash = {
:hidden_gateway_SN =>"<REPLACE WITH YOUR thermostat serial number>",
:pref_temp_units => "0",
:userid => "<REPLACE WITH YOUR USERNAME>",
:Central_Zoned_Away => "2",
:Cancel_Away => "-1",
:current_prg => "2",
:current_mode => "1",
:CurrentBrowser =>"chrome",
:zoneNumber => "0",
:Current_Thermostat=>"0",
:alertViewTypes=>"0",
:alertTypes => "1",
:reminderTypes => "0"}
myjson = JSON.generate(my_hash)
p "CurrentDate,Cool_Set_Point,Indoor_Temp,Fan_Mode,Indoor_Humidity,System_Status"
lastupdate=0
while 1 do
response4 = RestClient.post(
'https://www.myicomfort.com/Dashboard.aspx/NewGetManualInfo',
myjson,
{:content_type => :json, :accept => :json, :cookies => @session_cookies} )
#{ |response, request, result, &block|
# if [301, 302, 307].include? response.code
# p response.cookies
# @session_cookies = response.cookies
# #response.follow_redirection(request, result, &block)
# response
# else
# p response
# response.return!(request, result, &block)
# end
#}
json_object = JSON.parse(response4)
d = JSON.parse(json_object['d'])
# pp d
# if #{lastupdate} != #{d['CurrentDate']}
if lastupdate != d['CurrentDate']
lastupdate = d['CurrentDate']
p "#{d['CurrentDate']},#{d['Cool_Set_Point']},#{d['Indoor_Temp']},#{d['Fan_Mode']},#{d['Indoor_Humidity']},#{d['System_Status']}"
end
sleep 1
end