Thursday, January 23, 2014

Radio Thermostat Auto-Away Script | Eric Woodruff's blog

Radio Thermostat Auto-Away Script | Eric Woodruff's blog





123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
#!/usr/bin/ruby
require 'rest-client'
require 'json'
require 'open-uri'
require 'xmlsimple'
INTERVAL=30
THRESHOLD=10
THERMOSTAT="10.0.0.4"
HOSTS=%w(10.0.0.16 10.0.0.17)
RELEASE = { :hold => 0 }
MODE_OFF = { :tmode => 0, :hold => 0 }
MODE_AUTO = { :tmode => 3, :hold => 0 }
HOLD_HEAT = { :tmode => 1, :hold => 1, :t_heat => 62 }
HOLD_COOL = { :tmode => 2, :hold => 1, :t_cool => 85 }
def detect
HOSTS.inject(0) { |value,host| (system "ping -qn -c1 -w1 #{host} >/dev/null 2>&1") ? value+1 : value }
end
def get(path = "tstat")
JSON.parse RestClient.get("http://#{THERMOSTAT}/#{path}", :accept => :json)
end
def post(data, path = "tstat")
puts "POST #{path} #{data.inspect}"
JSON.parse RestClient.post("http://#{THERMOSTAT}/#{path}", data.to_json, :content_type => :json, :accept => :json)
end
$away_state = nil
$return_state = nil
def is_away_state?
return true if $away_state.nil?
current_state = get
$away_state.each_pair do |k,v|
return false if current_state[k.to_s] != v
end
true
end
def home
puts "#{Time.now} home"
if not is_away_state?
puts "Thermostat was changed manually."
else
puts((post $return_state).inspect) if $return_state
end
puts get.inspect
puts
end
def away
puts "#{Time.now} away"
last_state = get
case last_state["tmode"]
when 0
$away_state = nil
$return_state = nil
puts "Thermostat is off."
when 1
$away_state = HOLD_HEAT
$return_state = RELEASE
when 2
$away_state = HOLD_COOL
$return_state = RELEASE
when 3
$away_state = MODE_OFF
$return_state = MODE_AUTO
end
puts((post $away_state).inspect) if $away_state
puts get.inspect
puts
end
def fetch_outside_temp
uri = open('http://api.wunderground.com/weatherstation/WXCurrentObXML.asp?ID=KORBEAVE40')
data = XmlSimple.xml_in(uri.read)
data['temp_f'].first.to_f.round if data['temp_f']
end
def night_mode
current_state = get
tout = fetch_outside_temp
if tout and current_state["tmode"] == 2 and tout >= 74 and tout < current_state["temp"]
puts "Meeting outside temp #{tout}"
puts post({ :t_cool => tout })
end
end
count=THRESHOLD/2
puts "Restart."
loop do
if 0 != detect
home if count >= THRESHOLD
begin
night_mode
rescue => error
error.backtrace
end
count = 0
else
if 5 < count and count < THRESHOLD
puts "#{Time.now} away check count=#{count}"
elsif THRESHOLD == count
away
end
count += 1
end
sleep INTERVAL
end

No comments:

The Network