sappho-heatmiser-proxy 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
4
+ # This software is licensed under the GNU Affero General Public License, version 3.
5
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
6
+ # Copyright 2012 Andrew Heald.
7
+
8
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
9
+
10
+ require 'sappho-heatmiser-proxy'
11
+
12
+ Sappho::Heatmiser::Proxy::CommandLine.process
@@ -0,0 +1,28 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'sappho-heatmiser-proxy/heatmiser'
11
+ require 'sappho-heatmiser-proxy/heatmiser_proxy'
12
+ require 'thread'
13
+
14
+ class CommandLine
15
+
16
+ def CommandLine.process
17
+ Thread.abort_on_exception = true
18
+ hm = Heatmiser.new
19
+ hm.monitor
20
+ HeatmiserProxy.new.serve
21
+ hm.wait
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,62 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'singleton'
11
+ require 'thread'
12
+ require 'sappho-heatmiser-proxy/trace_log'
13
+ require 'sappho-heatmiser-proxy/system_configuration'
14
+
15
+ class ClientRegister
16
+
17
+ include Singleton
18
+
19
+ def initialize
20
+ @mutex = Mutex.new
21
+ @clients = {}
22
+ @max = Integer SystemConfiguration.instance.config['heatmiser.clients.max']
23
+ @log = TraceLog.instance
24
+ end
25
+
26
+ def register client
27
+ @mutex.synchronize do
28
+ ip = client.getpeername
29
+ @clients[client] = ip = (4 ... 8).map{|pos|ip[pos]}.join('.')
30
+ @log.info "client #{ip} connected"
31
+ log
32
+ end
33
+ end
34
+
35
+ def unregister client
36
+ @mutex.synchronize do
37
+ ip = @clients[client]
38
+ @clients.delete client
39
+ @log.info "client #{ip} disconnected"
40
+ log
41
+ end
42
+ end
43
+
44
+ def ip client
45
+ @mutex.synchronize { @clients[client] }
46
+ end
47
+
48
+ def maxAlreadyConnected?
49
+ @mutex.synchronize { @clients.size >= @max }
50
+ end
51
+
52
+ private
53
+
54
+ def log
55
+ @log.info "clients: #{@clients.size > 0 ? (@clients.collect{|client, ip| ip}).join(', ') : 'none'}"
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,60 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'singleton'
11
+ require 'thread'
12
+ require 'sappho-heatmiser-proxy/trace_log'
13
+
14
+ class CommandQueue
15
+
16
+ include Singleton
17
+
18
+ def initialize
19
+ @queue = []
20
+ @mutex = Mutex.new
21
+ @log = TraceLog.instance
22
+ end
23
+
24
+ def push clientIP, command
25
+ @log.info "client #{clientIP} requests command: #{TraceLog.hex command}"
26
+ @mutex.synchronize do
27
+ @queue << {
28
+ :clientIP => clientIP,
29
+ :command => command.dup
30
+ }
31
+ end
32
+ end
33
+
34
+ def get
35
+ command = nil
36
+ @mutex.synchronize do
37
+ if @queue.size > 0
38
+ queue = @queue[0]
39
+ command = queue[:command].dup
40
+ @log.info "client #{queue[:clientIP]} command executing: #{TraceLog.hex command}"
41
+ end
42
+ end
43
+ command
44
+ end
45
+
46
+ def completed
47
+ @mutex.synchronize do
48
+ if @queue.size > 0
49
+ queue = @queue[0]
50
+ @log.info "client #{queue[:clientIP]} command completed: #{TraceLog.hex queue[:command]}"
51
+ @queue.shift
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,107 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'sappho-heatmiser-proxy/heatmiser_crc'
11
+ require 'sappho-heatmiser-proxy/heatmiser_status'
12
+ require 'sappho-heatmiser-proxy/trace_log'
13
+ require 'sappho-heatmiser-proxy/command_queue'
14
+ require 'thread'
15
+ require 'timeout'
16
+ require 'socket'
17
+ require 'sappho-heatmiser-proxy/system_configuration'
18
+
19
+ class Heatmiser
20
+
21
+ def monitor
22
+ @thread = Thread.new do
23
+ status = HeatmiserStatus.instance
24
+ queue = CommandQueue.instance
25
+ log = TraceLog.instance
26
+ config = SystemConfiguration.instance.config
27
+ hostname = config['heatmiser.address']
28
+ port = Integer config['heatmiser.port']
29
+ pin = Integer config['heatmiser.pin']
30
+ pinLo = pin & 0xFF
31
+ pinHi = (pin >> 8) & 0xFF
32
+ queryCommand = HeatmiserCRC.new([0x93, 0x0B, 0x00, pinLo, pinHi, 0x00, 0x00, 0xFF, 0xFF]).appendCRC
33
+ loop do
34
+ status.invalidate
35
+ begin
36
+ log.info "opening connection to heatmiser at #{hostname}:#{port}"
37
+ TCPSocket.open hostname, port do | socket |
38
+ log.info "connected to heatmiser at #{hostname}:#{port}"
39
+ loop do
40
+ begin
41
+ sleep 5
42
+ command = queryCommand
43
+ if queuedCommand = queue.get
44
+ command = queuedCommand
45
+ else
46
+ if status.get{status.valid ? status.deviceTimeOffset : 0.0}.abs > 5.0
47
+ timeNow = Time.now
48
+ dayOfWeek = timeNow.wday
49
+ dayOfWeek = 7 if dayOfWeek == 0
50
+ command = HeatmiserCRC.new([0xA3, 0x12, 0x00, pinLo, pinHi, 0x01, 0x2B, 0x00, 0x07,
51
+ timeNow.year - 2000,
52
+ timeNow.month,
53
+ timeNow.day,
54
+ dayOfWeek,
55
+ timeNow.hour,
56
+ timeNow.min,
57
+ timeNow.sec]).appendCRC
58
+ log.info "clock correction: #{TraceLog.hex command}"
59
+ end
60
+ end
61
+ log.debug "sending command: #{TraceLog.hex command}" if log.debug?
62
+ reply = []
63
+ startTime = Time.now
64
+ timeout 20 do
65
+ socket.write command.pack('c*')
66
+ reply = socket.read(81).unpack('c*')
67
+ end
68
+ timestamp = Time.now
69
+ log.debug "reply: #{TraceLog.hex reply}" if log.debug?
70
+ crcHi = reply.pop & 0xFF
71
+ crcLo = reply.pop & 0xFF
72
+ crc = HeatmiserCRC.new reply
73
+ if (reply[0] & 0xFF) == 0x94 and reply[1] == 0x51 and reply[2] == 0 and
74
+ crc.crcHi == crcHi and crc.crcLo == crcLo
75
+ reply << crcLo << crcHi
76
+ status.set reply, timestamp, (timestamp - startTime) do
77
+ queue.completed if queuedCommand
78
+ end
79
+ end
80
+ rescue Timeout::Error
81
+ log.info "heatmiser at #{hostname}:#{port} is not responding - assuming connection down"
82
+ break
83
+ rescue => error
84
+ log.error error
85
+ break
86
+ end
87
+ end
88
+ log.info "closing connection to heatmiser at #{hostname}:#{port}"
89
+ socket.close
90
+ end
91
+ rescue => error
92
+ log.error error
93
+ end
94
+ sleep 10
95
+ end
96
+ end
97
+ end
98
+
99
+ def wait
100
+ @thread.join
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,70 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'thread'
11
+ require 'socket'
12
+ require 'sappho-heatmiser-proxy/trace_log'
13
+ require 'sappho-heatmiser-proxy/heatmiser_status'
14
+ require 'sappho-heatmiser-proxy/command_queue'
15
+ require 'sappho-heatmiser-proxy/client_register'
16
+
17
+ class HeatmiserClient
18
+
19
+ def session client
20
+ @clients = ClientRegister.instance
21
+ @clients.register client
22
+ @ip = @clients.ip client
23
+ @client = client
24
+ @status = HeatmiserStatus.instance
25
+ @log = TraceLog.instance
26
+ Thread.new do
27
+ loop do
28
+ begin
29
+ timeout 20 do
30
+ command = read 5
31
+ @log.debug "header: #{TraceLog.hex command}" if @log.debug?
32
+ packetSize = (command[1] & 0xFF) | ((command[2] << 8) & 0x0F00)
33
+ command += read(packetSize - 5)
34
+ CommandQueue.instance.push @ip, command unless (command[0] & 0xFF) == 0x93
35
+ @status.get { @client.write @status.raw.pack('c*') if @status.valid }
36
+ @log.info "command received from client #{@ip} so it is alive"
37
+ end
38
+ rescue Timeout::Error
39
+ @log.info "no command received from client #{@ip} so presuming it dormant"
40
+ break
41
+ rescue HeatmiserClient::ReadError
42
+ @log.info "unable to receive data from client #{@ip} so presuming it has disconnected"
43
+ break
44
+ rescue => error
45
+ @log.error error
46
+ break
47
+ end
48
+ end
49
+ begin
50
+ @client.close
51
+ rescue
52
+ end
53
+ @clients.unregister @client
54
+ end
55
+ end
56
+
57
+ def read size
58
+ data = @client.read size
59
+ raise HeatmiserClient::ReadError unless data and data.size == size
60
+ data.unpack('c*')
61
+ end
62
+
63
+ class ReadError < Interrupt
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,48 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ class HeatmiserCRC
11
+
12
+ LookupHi = [
13
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
14
+ 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1
15
+ ]
16
+ LookupLo = [
17
+ 0x00, 0x21, 0x42, 0x63, 0x84, 0xA5, 0xC6, 0xE7,
18
+ 0x08, 0x29, 0x4A, 0x6B, 0x8C, 0xAD, 0xCE, 0xEF
19
+ ]
20
+ attr_reader :crcHi, :crcLo
21
+
22
+ def initialize bytes
23
+ @bytes = bytes
24
+ @crcHi = 0xFF
25
+ @crcLo = 0xFF
26
+ bytes.each do |byte|
27
+ addNibble byte >> 4
28
+ addNibble byte & 0x0F
29
+ end
30
+ end
31
+
32
+ def appendCRC
33
+ @bytes << @crcLo << @crcHi
34
+ end
35
+
36
+ private
37
+
38
+ def addNibble nibble
39
+ t = ((@crcHi >> 4) ^ nibble) & 0x0F
40
+ @crcHi = (((@crcHi << 4) & 0xFF) | (@crcLo >> 4)) ^ LookupHi[t]
41
+ @crcLo = ((@crcLo << 4) & 0xFF) ^ LookupLo[t]
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'sappho-heatmiser-proxy/heatmiser_client'
11
+ require 'sappho-heatmiser-proxy/client_register'
12
+ require 'thread'
13
+ require 'socket'
14
+ require 'sappho-heatmiser-proxy/trace_log'
15
+
16
+ class HeatmiserProxy
17
+
18
+ def serve
19
+ Thread.new do
20
+ clients = ClientRegister.instance
21
+ port = Integer SystemConfiguration.instance.config['heatmiser.port']
22
+ log = TraceLog.instance
23
+ log.info "opening proxy server port #{port}"
24
+ TCPServer.open port do | server |
25
+ log.info "proxy server port #{port} is now open"
26
+ loop do
27
+ if clients.maxAlreadyConnected?
28
+ sleep 1
29
+ else
30
+ log.info "listening for new clients on proxy server port #{port}"
31
+ HeatmiserClient.new.session server.accept
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,136 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'singleton'
11
+ require 'thread'
12
+ require 'sappho-heatmiser-proxy/trace_log'
13
+
14
+ class HeatmiserStatus
15
+
16
+ include Singleton
17
+
18
+ attr_reader :valid, :timestamp, :sampleTime, :timeSinceLastValid, :sensedTemperature,
19
+ :requestedTemperature, :heatOn, :keyLockOn, :frostProtectOn, :deviceTimeOffset,
20
+ :dayOfWeek, :schedule
21
+
22
+ class TimedTemperature
23
+
24
+ attr_reader :hour, :minute, :temperature
25
+
26
+ def initialize raw, bytePosition
27
+ @hour = raw[bytePosition] & 0xFF
28
+ @minute = raw[bytePosition + 1] & 0xFF
29
+ @temperature = raw[bytePosition + 2] & 0xFF
30
+ end
31
+
32
+ def valid?
33
+ @hour < 24 and @minute < 60
34
+ end
35
+
36
+ def description
37
+ "#{@hour}:#{@minute}-#{@temperature}"
38
+ end
39
+
40
+ end
41
+
42
+ class Schedule
43
+
44
+ attr_reader :schedule
45
+
46
+ def initialize raw, bytePosition
47
+ @schedule = []
48
+ (0 ... 4).map do |position|
49
+ timedTemperature = TimedTemperature.new(raw, bytePosition + 3 * position)
50
+ @schedule << timedTemperature if timedTemperature.valid?
51
+ end
52
+ end
53
+
54
+ def description
55
+ (@schedule.collect {|timedTemperature| timedTemperature.description}).join(' ')
56
+ end
57
+
58
+ end
59
+
60
+ def initialize
61
+ @mutex = Mutex.new
62
+ @log = TraceLog.instance
63
+ @valid = false
64
+ @raw = []
65
+ @timestamp = Time.now
66
+ @sampleTime = 0.0
67
+ @timeSinceLastValid = 0.0
68
+ @sensedTemperature = 0.0
69
+ @requestedTemperature = 0
70
+ @holidayReturnTime = Time.now
71
+ @holdMinutes = 0
72
+ @heatOn = false
73
+ @keyLockOn = false
74
+ @frostProtectOn = false
75
+ @holidayOn = false
76
+ @deviceTimeOffset = 0.0
77
+ @dayOfWeek = 0
78
+ @schedule = {}
79
+ end
80
+
81
+ def raw
82
+ @raw.dup
83
+ end
84
+
85
+ def get
86
+ @mutex.synchronize { yield }
87
+ end
88
+
89
+ def set raw, timestamp, sampleTime
90
+ @mutex.synchronize do
91
+ @valid = true
92
+ begin
93
+ @raw = raw.dup
94
+ @sensedTemperature = ((raw[44] & 0xFF) | ((raw[45] << 8) & 0xFF00)) / 10.0
95
+ @holdMinutes = (raw[38] & 0xFF) | ((raw[39] << 8) & 0xFF00)
96
+ @heatOn = raw[47] == 1
97
+ @keyLockOn = raw[29] == 1
98
+ @frostProtectOn = raw[30] == 1
99
+ @holidayOn = raw[37] == 1
100
+ @holidayReturnTime = Time.local(2000 + (raw[32] & 0xFF), raw[33], raw[34], raw[35], raw[36], 0)
101
+ @requestedTemperature = @frostProtectOn ? raw[24] & 0xFF : raw[25] & 0xFF
102
+ @deviceTimeOffset = Time.local(2000 + (raw[48] & 0xFF), raw[49], raw[50],
103
+ raw[52], raw[53], raw[54]) - timestamp
104
+ dayOfWeek = raw[51]
105
+ @dayOfWeek = dayOfWeek == 7 ? 0 : dayOfWeek
106
+ @schedule = {
107
+ :weekday => Schedule.new(@raw, 55),
108
+ :weekend => Schedule.new(@raw, 67)
109
+ }
110
+ @timeSinceLastValid = timestamp - @timestamp
111
+ @timestamp = timestamp
112
+ @sampleTime = sampleTime
113
+ if @log.debug?
114
+ @log.debug "#{TraceLog.hex raw}"
115
+ @log.debug "#{@requestedTemperature} #{@holdMinutes / 60}:#{@holdMinutes % 60} #{@sensedTemperature} #{@heatOn} #{@keyLockOn} #{@frostProtectOn} #{@timeSinceLastValid} #{@dayOfWeek} #{@deviceTimeOffset} #{sampleTime} #{@holidayOn} #{@holidayReturnTime}"
116
+ @log.debug "weekday: #{@schedule[:weekday].description} weekend: #{@schedule[:weekend].description}"
117
+ else
118
+ @log.info "received status: heating is #{@heatOn ? "on" : "off"} because required temperature is #{@requestedTemperature} and actual is #{@sensedTemperature}"
119
+ end
120
+ yield
121
+ rescue => error
122
+ @log.error error
123
+ @valid = false
124
+ end
125
+ end
126
+ end
127
+
128
+ def invalidate
129
+ @mutex.synchronize { @valid = false }
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,27 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'singleton'
11
+ require 'yaml'
12
+
13
+ class SystemConfiguration
14
+
15
+ include Singleton
16
+
17
+ attr_reader :config
18
+
19
+ def initialize
20
+ @config = YAML.load_file(File.expand_path(ARGV[0] || 'heatmiser-proxy.yml'))
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,60 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+
10
+ require 'singleton'
11
+ require 'thread'
12
+ require 'logger'
13
+ require 'sappho-heatmiser-proxy/system_configuration'
14
+ require 'sappho-heatmiser-proxy/version'
15
+
16
+ class TraceLog
17
+
18
+ include Singleton
19
+
20
+ def initialize
21
+ @mutex = Mutex.new
22
+ config = SystemConfiguration.instance.config
23
+ @log = Logger.new(config['log.stdout'] ? STDOUT : config['log.filename'])
24
+ @log.level = config['log.debug'] ? Logger::DEBUG : Logger::INFO
25
+ @log.formatter = proc { |severity, datetime, progname, message| "#{message}\n" }
26
+ @log.info "#{NAME} version #{VERSION} - #{HOMEPAGE}"
27
+ end
28
+
29
+ def info message
30
+ @mutex.synchronize do
31
+ @log.info message
32
+ end if @log.info?
33
+ end
34
+
35
+ def debug message
36
+ @mutex.synchronize do
37
+ @log.debug message
38
+ end if @log.debug?
39
+ end
40
+
41
+ def error error
42
+ @mutex.synchronize do
43
+ @log.error "error! #{error.message}"
44
+ error.backtrace.each { |error| @log.error error }
45
+ end if @log.error?
46
+ end
47
+
48
+ def debug?
49
+ @log.debug?
50
+ end
51
+
52
+ def TraceLog.hex bytes
53
+ (bytes.collect {|byte| "%02x " % (byte & 0xFF)}).join
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,18 @@
1
+ # See https://github.com/sappho/sappho-heatmiser-proxy/wiki for project documentation.
2
+ # This software is licensed under the GNU Affero General Public License, version 3.
3
+ # See http://www.gnu.org/licenses/agpl.html for full details of the license terms.
4
+ # Copyright 2012 Andrew Heald.
5
+
6
+ module Sappho
7
+ module Heatmiser
8
+ module Proxy
9
+ NAME = "sappho-heatmiser-proxy"
10
+ VERSION = "0.0.1"
11
+ AUTHORS = ["Andrew Heald"]
12
+ EMAILS = ["andrew@heald.co.uk"]
13
+ HOMEPAGE = "https://github.com/sappho/sappho-heatmiser-proxy/wiki"
14
+ SUMMARY = "Acts as a proxy for Heatmiser hardware to allow continuous monitoring and control by many controllers"
15
+ DESCRIPTION = "See the project home page for more information"
16
+ end
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sappho-heatmiser-proxy
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Andrew Heald
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-26 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rake
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 11
29
+ segments:
30
+ - 0
31
+ - 9
32
+ - 2
33
+ - 2
34
+ version: 0.9.2.2
35
+ type: :development
36
+ version_requirements: *id001
37
+ description: See the project home page for more information
38
+ email:
39
+ - andrew@heald.co.uk
40
+ executables:
41
+ - sappho-heatmiser-proxy
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - bin/sappho-heatmiser-proxy
48
+ - lib/sappho-heatmiser-proxy.rb
49
+ - lib/sappho-heatmiser-proxy/client_register.rb
50
+ - lib/sappho-heatmiser-proxy/command_queue.rb
51
+ - lib/sappho-heatmiser-proxy/heatmiser.rb
52
+ - lib/sappho-heatmiser-proxy/heatmiser_client.rb
53
+ - lib/sappho-heatmiser-proxy/heatmiser_crc.rb
54
+ - lib/sappho-heatmiser-proxy/heatmiser_proxy.rb
55
+ - lib/sappho-heatmiser-proxy/heatmiser_status.rb
56
+ - lib/sappho-heatmiser-proxy/system_configuration.rb
57
+ - lib/sappho-heatmiser-proxy/trace_log.rb
58
+ - lib/sappho-heatmiser-proxy/version.rb
59
+ homepage: https://github.com/sappho/sappho-heatmiser-proxy/wiki
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options: []
64
+
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project: sappho-heatmiser-proxy
88
+ rubygems_version: 1.8.17
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Acts as a proxy for Heatmiser hardware to allow continuous monitoring and control by many controllers
92
+ test_files: []
93
+