ansible4ozw 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ansible.rb +47 -0
- data/lib/ansible/ansible_callback.rb +142 -0
- data/lib/ansible/ansible_device.rb +68 -0
- data/lib/ansible/ansible_value.rb +179 -0
- data/lib/ansible/config.rb +92 -0
- data/lib/ansible/devices/ansible_dimmer.rb +80 -0
- data/lib/ansible/devices/ansible_switch.rb +66 -0
- data/lib/ansible/knx/EIBConnection.rb +2371 -0
- data/lib/ansible/knx/dpt/canonical_1bit.rb +54 -0
- data/lib/ansible/knx/dpt/dpt1.rb +224 -0
- data/lib/ansible/knx/dpt/dpt10.rb +85 -0
- data/lib/ansible/knx/dpt/dpt11.rb +72 -0
- data/lib/ansible/knx/dpt/dpt12.rb +61 -0
- data/lib/ansible/knx/dpt/dpt13.rb +100 -0
- data/lib/ansible/knx/dpt/dpt14.rb +87 -0
- data/lib/ansible/knx/dpt/dpt15.rb +72 -0
- data/lib/ansible/knx/dpt/dpt16.rb +67 -0
- data/lib/ansible/knx/dpt/dpt17.rb +65 -0
- data/lib/ansible/knx/dpt/dpt18.rb +66 -0
- data/lib/ansible/knx/dpt/dpt19.rb +100 -0
- data/lib/ansible/knx/dpt/dpt2.rb +156 -0
- data/lib/ansible/knx/dpt/dpt3.rb +104 -0
- data/lib/ansible/knx/dpt/dpt4.rb +75 -0
- data/lib/ansible/knx/dpt/dpt5.rb +124 -0
- data/lib/ansible/knx/dpt/dpt6.rb +73 -0
- data/lib/ansible/knx/dpt/dpt7.rb +146 -0
- data/lib/ansible/knx/dpt/dpt8.rb +118 -0
- data/lib/ansible/knx/dpt/dpt9.rb +204 -0
- data/lib/ansible/knx/dpt/tests/test_dpt10.rb +45 -0
- data/lib/ansible/knx/dpt/tests/test_dpt9.rb +60 -0
- data/lib/ansible/knx/hexdump.rb +113 -0
- data/lib/ansible/knx/knx_dpt.rb +58 -0
- data/lib/ansible/knx/knx_dpt_scalar.rb +62 -0
- data/lib/ansible/knx/knx_eistypes.rb +76 -0
- data/lib/ansible/knx/knx_protocol.rb +99 -0
- data/lib/ansible/knx/knx_scene.rb +48 -0
- data/lib/ansible/knx/knx_tools.rb +76 -0
- data/lib/ansible/knx/knx_transceiver.rb +237 -0
- data/lib/ansible/knx/knx_value.rb +327 -0
- data/lib/ansible/openzwave/ozw_constants.rb +11 -0
- data/lib/ansible/openzwave/ozw_headers.rb +80 -0
- data/lib/ansible/openzwave/ozw_remote_manager.rb +7615 -0
- data/lib/ansible/openzwave/ozw_types.rb +406 -0
- data/lib/ansible/orbiter_proxy.rb +12 -0
- data/lib/ansible/transceiver.rb +63 -0
- data/lib/ansible/zwave/types/valuetype_bool.rb +74 -0
- data/lib/ansible/zwave/types/valuetype_button.rb +63 -0
- data/lib/ansible/zwave/types/valuetype_byte.rb +78 -0
- data/lib/ansible/zwave/types/valuetype_decimal.rb +64 -0
- data/lib/ansible/zwave/types/valuetype_int.rb +63 -0
- data/lib/ansible/zwave/types/valuetype_list.rb +64 -0
- data/lib/ansible/zwave/types/valuetype_short.rb +63 -0
- data/lib/ansible/zwave/types/valuetype_string.rb +61 -0
- data/lib/ansible/zwave/zwave_command_classes.rb +113 -0
- data/lib/ansible/zwave/zwave_node.rb +5 -0
- data/lib/ansible/zwave/zwave_protocol.rb +52 -0
- data/lib/ansible/zwave/zwave_transceiver.rb +435 -0
- data/lib/ansible/zwave/zwave_value.rb +193 -0
- metadata +108 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
|
3
|
+
class DPT10 < BinData::Record
|
4
|
+
bit3 :dayofweek, {
|
5
|
+
:display_name => "Day of week",
|
6
|
+
:range => 0..7, :data_desc => {
|
7
|
+
0 => "(no day set)",
|
8
|
+
1 => "Monday",
|
9
|
+
2 => "Tuesday",
|
10
|
+
3 => "Wednesday",
|
11
|
+
4 => "Thursday",
|
12
|
+
5 => "Friday",
|
13
|
+
6 => "Saturday",
|
14
|
+
7 => "Sunday"
|
15
|
+
}
|
16
|
+
}
|
17
|
+
bit5 :hour, {
|
18
|
+
:display_name => "Hour", :range => 0..23
|
19
|
+
}
|
20
|
+
#
|
21
|
+
bit2 :unused1
|
22
|
+
bit6 :minutes, {
|
23
|
+
:display_name => "Minutes", :range => 0..59
|
24
|
+
}
|
25
|
+
#
|
26
|
+
bit2 :unused2
|
27
|
+
bit6 :seconds, {
|
28
|
+
:display_name => "Seconds", :range => 0..59
|
29
|
+
}
|
30
|
+
end
|
31
|
+
[
|
32
|
+
[0x8e, 0x21, 0x00]
|
33
|
+
].each {|arr|
|
34
|
+
f = DPT10.read(arr.pack('C*'))
|
35
|
+
puts arr.inspect + " ==> " + f.inspect
|
36
|
+
# f.data = -10
|
37
|
+
# puts "after set() ==> " + f.inspect + " serialized as " + f.to_binary_s.unpack("H*").join('0x')
|
38
|
+
#f.dayofweek.get_parameter(:range)
|
39
|
+
}
|
40
|
+
=begin
|
41
|
+
[
|
42
|
+
# DPT11.001 date
|
43
|
+
[0x17, 0x01, 0x0C] # 23/Jan/2012
|
44
|
+
].each {|arr|
|
45
|
+
=end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
|
3
|
+
class DPT9_Float < BinData::Primitive
|
4
|
+
endian :big
|
5
|
+
#
|
6
|
+
bit1 :sign, :display_name => "Sign"
|
7
|
+
bit4 :exp, :display_name => "Exponent"
|
8
|
+
bit11 :mant, :display_name => "Mantissa"
|
9
|
+
#
|
10
|
+
def get
|
11
|
+
puts "get, sign=#{sign} exp=#{exp} mant=#{mant}"
|
12
|
+
mantissa = (self.sign==1) ? ~(self.mant^2047) : self.mant
|
13
|
+
return Math.ldexp((0.01*mantissa), self.exp)
|
14
|
+
end
|
15
|
+
#
|
16
|
+
def set(v)
|
17
|
+
mantissa, exponent = Math.frexp(v)
|
18
|
+
puts "#{self}.set(#{v}) with initial mantissa=#{mantissa}, exponent=#{exponent}"
|
19
|
+
# find the minimum exponent that will upsize the normalized mantissa (0,5 to 1 range)
|
20
|
+
# in order to fit in 11 bits (-2048..2047)
|
21
|
+
max_mantissa = 0
|
22
|
+
minimum_exp = exponent.downto(-15).find{ | e |
|
23
|
+
max_mantissa = Math.ldexp(100*mantissa, e).to_i
|
24
|
+
max_mantissa.between?(-2048, 2047)
|
25
|
+
}
|
26
|
+
self.sign = (mantissa < 0) ? 1 : 0
|
27
|
+
self.mant = (mantissa < 0) ? ~(max_mantissa^2047) : max_mantissa
|
28
|
+
self.exp = exponent - minimum_exp
|
29
|
+
puts "... set(#{v}) finished: sign=#{sign}, mantissa=#{mant}, exponent=#{exp}"
|
30
|
+
end # set
|
31
|
+
end
|
32
|
+
|
33
|
+
class DPT9 < BinData::Record
|
34
|
+
dpt9_float :data
|
35
|
+
end
|
36
|
+
|
37
|
+
{
|
38
|
+
#forward test (raw data to float)
|
39
|
+
DPT9.read([0x00, 0x02].pack('C*')).data => 0.02,
|
40
|
+
DPT9.read([0x87, 0xfe].pack('C*')).data => -0.02,
|
41
|
+
DPT9.read([0x5c, 0xc4].pack('C*')).data => 24980..25000,
|
42
|
+
DPT9.read([0xdb, 0x3c].pack('C*')).data => -25000..-24980,
|
43
|
+
DPT9.read([0x7f, 0xfe].pack('C*')).data => 670400..670760,
|
44
|
+
DPT9.read([0xf8, 0x02].pack('C*')).data => -670760..-670400,
|
45
|
+
#backward test (float to raw data)
|
46
|
+
"----" => "----",
|
47
|
+
DPT9_Float.new(0.02).to_binary_s.unpack("C*") => [0x00, 0x02],
|
48
|
+
DPT9_Float.new(-0.02).to_binary_s.unpack("C*") => [0x87, 0xfe],
|
49
|
+
DPT9_Float.new(25000).to_binary_s.unpack("C*") => [0x5c, 0xc4],
|
50
|
+
DPT9_Float.new(-25000).to_binary_s.unpack("C*") => [0xdb, 0x3c],
|
51
|
+
DPT9_Float.new(670760).to_binary_s.unpack("C*") => [0x7f, 0xfe],
|
52
|
+
DPT9_Float.new(-670760).to_binary_s.unpack("C*") => [0xf8, 0x02],
|
53
|
+
}.each {|arr, test|
|
54
|
+
#f = DPT9.read(arr.pack('C*'))
|
55
|
+
puts arr.inspect + " ==> " + test.inspect + " \t TEST: " + (test === arr ? 'ok':"\t---FAIL---")
|
56
|
+
# f.data = -30
|
57
|
+
# puts "after set() ==> " + f.inspect + " serialized as " + f.to_binary_s.unpack('B*').join(' ') + " (0x" + f.to_binary_s.unpack("H*").join('') + ")"
|
58
|
+
}
|
59
|
+
|
60
|
+
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# ==============================================================================
|
2
|
+
# EXTENDING CLASS STRING
|
3
|
+
# ==============================================================================
|
4
|
+
#
|
5
|
+
# (C) Copyright 2004 by Tilo Sloboda <tools@unixgods.org>
|
6
|
+
#
|
7
|
+
# License:
|
8
|
+
# Freely available under the terms of the OpenSource "Artistic License"
|
9
|
+
# in combination with the Addendum A (below)
|
10
|
+
#
|
11
|
+
# In case you did not get a copy of the license along with the software,
|
12
|
+
# it is also available at: http://www.unixgods.org/~tilo/artistic-license.html
|
13
|
+
#
|
14
|
+
# Addendum A:
|
15
|
+
# THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU!
|
16
|
+
# SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
17
|
+
# REPAIR OR CORRECTION.
|
18
|
+
#
|
19
|
+
# IN NO EVENT WILL THE COPYRIGHT HOLDERS BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
|
20
|
+
# SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY
|
21
|
+
# TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
|
22
|
+
# INACCURATE OR USELESS OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
|
23
|
+
# TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF THE COPYRIGHT HOLDERS OR OTHER PARTY HAS BEEN
|
24
|
+
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
25
|
+
|
26
|
+
|
27
|
+
class String
|
28
|
+
#
|
29
|
+
# prints out a good'ol hexdump of the data contained in the string
|
30
|
+
#
|
31
|
+
# parameters: sparse: true / false do we want to print multiple lines with zero values?
|
32
|
+
|
33
|
+
def hexdump(sparse = false)
|
34
|
+
selfsize = self.size
|
35
|
+
first = true
|
36
|
+
|
37
|
+
print "\n index 0 1 2 3 4 5 6 7 8 9 A B C D E F\n\n"
|
38
|
+
|
39
|
+
lines,rest = selfsize.divmod(16)
|
40
|
+
address = 0; i = 0 # we count them independently for future extension.
|
41
|
+
|
42
|
+
while lines > 0
|
43
|
+
str = self[i..i+15]
|
44
|
+
|
45
|
+
# we don't print lines with all zeroes, unless it's the last line
|
46
|
+
|
47
|
+
if str == "\0"*16 # if the 16 bytes are all zero
|
48
|
+
|
49
|
+
if (!sparse) || (sparse && lines == 1 && rest == 0)
|
50
|
+
str.tr!("\000-\037\177-\377",'.')
|
51
|
+
printf( "%08x %8s %8s %8s %8s %s\n",
|
52
|
+
address, self[i..i+3].unpack('H8'), self[i+4..i+7].unpack('H8'),
|
53
|
+
self[i+8..i+11].unpack('H8'), self[i+12..i+15].unpack('H8'), str)
|
54
|
+
else
|
55
|
+
print " .... 00 .. 00 00 .. 00 00 .. 00 00 .. 00 ................\n" if first
|
56
|
+
first = false
|
57
|
+
end
|
58
|
+
|
59
|
+
else # print string which is not all zeros
|
60
|
+
|
61
|
+
str.tr!("\000-\037\177-\377",'.')
|
62
|
+
printf( "%08x %8s %8s %8s %8s %s\n",
|
63
|
+
address, self[i..i+3].unpack('H8'), self[i+4..i+7].unpack('H8'),
|
64
|
+
self[i+8..i+11].unpack('H8'), self[i+12..i+15].unpack('H8'), str)
|
65
|
+
first = true
|
66
|
+
end
|
67
|
+
i += 16; address += 16; lines -= 1
|
68
|
+
end
|
69
|
+
|
70
|
+
# now do the remaining bytes, which don't fit a full line..
|
71
|
+
# yikes - this is truly ugly! REWRITE THIS!!
|
72
|
+
|
73
|
+
if rest > 0
|
74
|
+
chunks2,rest2 = rest.divmod(4)
|
75
|
+
j = i; k = 0
|
76
|
+
if (i < selfsize)
|
77
|
+
printf( "%08x ", address)
|
78
|
+
while (i < selfsize)
|
79
|
+
printf "%02x", self[i]
|
80
|
+
i += 1; k += 1
|
81
|
+
print " " if ((i % 4) == 0)
|
82
|
+
end
|
83
|
+
for i in (k..15)
|
84
|
+
print " "
|
85
|
+
end
|
86
|
+
str = self[j..selfsize]
|
87
|
+
str.tr!("\000-\037\177-\377",'.')
|
88
|
+
print " " * (4 - chunks2+1)
|
89
|
+
printf(" %s\n", str)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
__END__
|
99
|
+
|
100
|
+
require 'hexdump'
|
101
|
+
|
102
|
+
s = "some random long string"
|
103
|
+
|
104
|
+
t = s << "\0"*40 << s << "\0"*32 << s << "bla bla bla!"
|
105
|
+
t.hexdump(true)
|
106
|
+
t.hexdump(false)
|
107
|
+
|
108
|
+
4.times {t.chop!}
|
109
|
+
|
110
|
+
t.hexdump(true)
|
111
|
+
t.hexdump(false)
|
112
|
+
|
113
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
=begin
|
2
|
+
Project Ansible - An extensible home automation scripting framework
|
3
|
+
----------------------------------------------------
|
4
|
+
Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
5
|
+
|
6
|
+
SOFTWARE NOTICE AND LICENSE
|
7
|
+
|
8
|
+
Project Ansible is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU Lesser General Public License as published
|
10
|
+
by the Free Software Foundation, either version 3 of the License,
|
11
|
+
or (at your option) any later version.
|
12
|
+
|
13
|
+
Project Ansible is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Lesser General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Lesser General Public License
|
19
|
+
along with Project Ansible. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
for more information on the LGPL, see:
|
22
|
+
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
23
|
+
=end
|
24
|
+
|
25
|
+
require 'bindata'
|
26
|
+
|
27
|
+
module Ansible
|
28
|
+
|
29
|
+
module KNX
|
30
|
+
|
31
|
+
# a base class for DPT data structures.
|
32
|
+
# derives from BinData::Record,
|
33
|
+
# implements some common stuff
|
34
|
+
class DPTFrame < BinData::Record
|
35
|
+
# endianness in KNX is big
|
36
|
+
endian :big
|
37
|
+
|
38
|
+
# make sure all frame fields are valid (within min,max range)
|
39
|
+
def validate_ranges()
|
40
|
+
# range checking is global: applies to all subtypes
|
41
|
+
field_names.each { |fieldname|
|
42
|
+
# skip padding fields
|
43
|
+
next if /pad/.match(fieldname)
|
44
|
+
field = self.send(fieldname)
|
45
|
+
if range = field.get_parameter(:range) then
|
46
|
+
raise "#{self}: field #{fieldname} value (#{field.value}) out of range #{range}" unless range === field.value
|
47
|
+
end
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# load all known DPT modules
|
54
|
+
Dir["knx/dpt/*.rb"].each { |f| load f }
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
=begin
|
2
|
+
Project Ansible - An extensible home automation scripting framework
|
3
|
+
----------------------------------------------------
|
4
|
+
Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
5
|
+
|
6
|
+
SOFTWARE NOTICE AND LICENSE
|
7
|
+
|
8
|
+
Project Ansible is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU Lesser General Public License as published
|
10
|
+
by the Free Software Foundation, either version 3 of the License,
|
11
|
+
or (at your option) any later version.
|
12
|
+
|
13
|
+
Project Ansible is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Lesser General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Lesser General Public License
|
19
|
+
along with Project Ansible. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
for more information on the LGPL, see:
|
22
|
+
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
23
|
+
=end
|
24
|
+
|
25
|
+
module Ansible
|
26
|
+
|
27
|
+
module KNX
|
28
|
+
|
29
|
+
# KNX specification declares some special DPTs (5.001 and 5.003) that need
|
30
|
+
# scalar adjustment functions to get the true value contained in a DPT frame.
|
31
|
+
module ScalarValue
|
32
|
+
|
33
|
+
# convert value to its scalar representation
|
34
|
+
# e.g. in DPT5.001, 0x7F => 50(%), 0xFF => 100(%)
|
35
|
+
def to_scalar(val, data_range, scalar_range)
|
36
|
+
if data_range.is_a?(Range) and scalar_range.is_a?(Range) then
|
37
|
+
a = (scalar_range.max - scalar_range.min).to_f / (data_range.max - data_range.min)
|
38
|
+
b = (scalar_range.min - data_range.min)
|
39
|
+
return (a*val + b).round
|
40
|
+
else
|
41
|
+
return val
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# convert value from its scalar representation
|
46
|
+
# e.g. in DPT5.001, 50(%) => 0x7F , 100(%) => 0xFF
|
47
|
+
def from_scalar(val, data_range, scalar_range)
|
48
|
+
if data_range.is_a?(Range) and scalar_range.is_a?(Range) then
|
49
|
+
a = (scalar_range.max - scalar_range.min).to_f / (data_range.max - data_range.min)
|
50
|
+
b = (scalar_range.min - data_range.min)
|
51
|
+
#puts "a=#{a} b=#{b}"
|
52
|
+
return ((val - b) / a).round
|
53
|
+
else
|
54
|
+
return val
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
=begin
|
2
|
+
Project Ansible - An extensible home automation scripting framework
|
3
|
+
----------------------------------------------------
|
4
|
+
Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
5
|
+
|
6
|
+
SOFTWARE NOTICE AND LICENSE
|
7
|
+
|
8
|
+
Project Ansible is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU Lesser General Public License as published
|
10
|
+
by the Free Software Foundation, either version 3 of the License,
|
11
|
+
or (at your option) any later version.
|
12
|
+
|
13
|
+
Project Ansible is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Lesser General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Lesser General Public License
|
19
|
+
along with Project Ansible. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
for more information on the LGPL, see:
|
22
|
+
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
23
|
+
=end
|
24
|
+
|
25
|
+
module Ansible
|
26
|
+
|
27
|
+
module KNX
|
28
|
+
|
29
|
+
# the skeleton class for the datatypes in use by the KNX standard
|
30
|
+
class EISType
|
31
|
+
|
32
|
+
# singleton hash holding all known EISType instances
|
33
|
+
# key => primary_type (integer 1 to 255)
|
34
|
+
# value => hash of secondary types (secondary_type => instance)
|
35
|
+
# -- NOTE: the contained secondary types hash can be set
|
36
|
+
# to report a default instance that holds a generic EISType.
|
37
|
+
# Thus we define datatypes with great granularity.
|
38
|
+
@@alltypes = {}
|
39
|
+
|
40
|
+
# method for getting all known EIS types as a flat array
|
41
|
+
def EISType.all
|
42
|
+
return @@alltypes.values.collect{ |st| st.values + st.default}.flatten.compact
|
43
|
+
end
|
44
|
+
|
45
|
+
# initializes a new datatype
|
46
|
+
def initialize(primary_type, secondary_type)
|
47
|
+
puts "Initializing new EISType pri=#{primary_type} sec=#{secondary_type}"
|
48
|
+
@primary_type , @secondary_type = primary_type , secondary_type
|
49
|
+
@@alltypes[primary_type] = {} unless @@alltypes[primary_type].is_a? Hash
|
50
|
+
# store ourselves in the big hash of types
|
51
|
+
if secondary_type.nil? then
|
52
|
+
puts "==> Redeclaring default EISType for primary=#{primary_type}" if @@alltypes[primary_type]
|
53
|
+
@@alltypes[primary_type].default = self
|
54
|
+
else
|
55
|
+
@@alltypes[primary_type][secondary_type] = self
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# return a human-readable description for this EISType
|
60
|
+
def to_s
|
61
|
+
return 'EIS' + @primary_type.to_s + (@secondary_type.nil? ? "" : ".#{@secondary_type}")
|
62
|
+
end
|
63
|
+
|
64
|
+
# takes a KNX value and abstracts its data
|
65
|
+
# usage: eis1.abstractor {|value| value.to_s }
|
66
|
+
|
67
|
+
def abstractor=(&block)
|
68
|
+
# in its most basic form, abstract_value just returns the value
|
69
|
+
return(value.get()
|
70
|
+
end
|
71
|
+
|
72
|
+
end # class
|
73
|
+
|
74
|
+
end #module KNX
|
75
|
+
|
76
|
+
end #module Ansible
|
@@ -0,0 +1,99 @@
|
|
1
|
+
=begin
|
2
|
+
Project Ansible - An extensible home automation scripting framework
|
3
|
+
----------------------------------------------------
|
4
|
+
Copyright (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
|
5
|
+
|
6
|
+
SOFTWARE NOTICE AND LICENSE
|
7
|
+
|
8
|
+
Project Ansible is free software: you can redistribute it and/or modify
|
9
|
+
it under the terms of the GNU Lesser General Public License as published
|
10
|
+
by the Free Software Foundation, either version 3 of the License,
|
11
|
+
or (at your option) any later version.
|
12
|
+
|
13
|
+
Project Ansible is distributed in the hope that it will be useful,
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
GNU Lesser General Public License for more details.
|
17
|
+
|
18
|
+
You should have received a copy of the GNU Lesser General Public License
|
19
|
+
along with Project Ansible. If not, see <http://www.gnu.org/licenses/>.
|
20
|
+
|
21
|
+
for more information on the LGPL, see:
|
22
|
+
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
|
23
|
+
=end
|
24
|
+
|
25
|
+
require 'bindata'
|
26
|
+
|
27
|
+
module Ansible
|
28
|
+
|
29
|
+
module KNX
|
30
|
+
|
31
|
+
# the basic Control field structure for KNX/TP (Twisted Pair) telegrams
|
32
|
+
# contains only low-level transmission medium data
|
33
|
+
class TP_ControlField < BinData::Record
|
34
|
+
bit2 :lpdu_code, { :display_name => "LPDU (2bit) 2=L_DATA.req 3=L_Poll_data.req" }
|
35
|
+
bit1 :rep_flag, { :display_name => "Repeat flag"}
|
36
|
+
bit1 :ack_not, { :display_name => "0 = Acknowledge frame, 1 = standard frame"}
|
37
|
+
bit2 :prio_class,{ :display_name => "Priority class (0=highest .. 3=lowest)"}
|
38
|
+
bit2 :unused1, { :display_name => "two unused bits (should be 00)"}
|
39
|
+
end
|
40
|
+
|
41
|
+
# same as TP_ControlField, plus network- and application-layer data
|
42
|
+
# also known as APDU (Application Datagram Unit)
|
43
|
+
class L_DATA_Frame < BinData::Record
|
44
|
+
endian :big
|
45
|
+
# octet 0: TP1 control field
|
46
|
+
bit2 :lpdu_code, { :display_name => "LPDU (2bit) 2=L_DATA.req 3=L_Poll_data.req"}
|
47
|
+
bit1 :rep_flag, { :display_name => "Repeat flag"}
|
48
|
+
bit1 :ack_not, { :display_name => "0 = Acknowledge frame, 1 = standard frame"}
|
49
|
+
bit2 :prio_class,{ :display_name => "Priority class (0=highest .. 3=lowest)"}
|
50
|
+
bit2 :unused1, { :display_name => "two unused bits (should be 00)"}
|
51
|
+
# octet 1+2: source
|
52
|
+
uint16 :src_addr, { :display_name => "Source Address"}
|
53
|
+
# octet 3+4: destination
|
54
|
+
uint16 :dst_addr, { :display_name => "Destination Address"}
|
55
|
+
# octet 5: control fields
|
56
|
+
bit1 :daf, { :display_name => "Dest.Address flag 0=physical 1=group"}
|
57
|
+
bit3 :ctrlfield, { :display_name => "Network control field"}
|
58
|
+
bit4 :datalength,{ :display_name => "Data length (bytes after octet #6)"}
|
59
|
+
# octet 6 + octet 7: TPCI+APCI+6-bit data
|
60
|
+
bit2 :tpci, { :display_name => "TPCI control bits 8+7"}
|
61
|
+
bit4 :seq, { :display_name => "Packet sequence"}
|
62
|
+
bit4 :apci, { :display_name => "APCI control bits"}
|
63
|
+
bit6 :apci_data, { :display_name => "APCI/Data combined"}
|
64
|
+
# octet 8 .. end
|
65
|
+
string :data, {
|
66
|
+
:read_length => lambda { datalength - 1 },
|
67
|
+
:display_nane => "rest of frame"
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
#########################################################
|
72
|
+
|
73
|
+
# APCI codes array
|
74
|
+
APCICODES = "A_GroupValue_Read A_GroupValue_Response A_GroupValue_Write \
|
75
|
+
A_PhysicalAddress_Write A_PhysicalAddress_Read A_PhysicalAddress_Response \
|
76
|
+
A_ADC_Read A_ADC_Response A_Memory_Read A_Memory_Response A_Memory_Write \
|
77
|
+
A_UserMemory A_DeviceDescriptor_Read A_DeviceDescriptor_Response A_Restart \
|
78
|
+
A_OTHER".split()
|
79
|
+
|
80
|
+
# TPDU codes array
|
81
|
+
TPDUCODES = "T_DATA_XXX_REQ T_DATA_CONNECTED_REQ T_DISCONNECT_REQ T_ACK".split()
|
82
|
+
|
83
|
+
# Priority classes
|
84
|
+
PRIOCLASSES = "system alarm high low".split()
|
85
|
+
|
86
|
+
#########################################################
|
87
|
+
|
88
|
+
end #module KNX
|
89
|
+
|
90
|
+
end #module
|
91
|
+
|
92
|
+
#~ data = [188, 17, 200, 18, 1, 242, 0, 128, 80, 171] .pack("c*")
|
93
|
+
#~ knxpacket = KNX_L_DATA_Frame.new(data)
|
94
|
+
#~ knxpacket.fields.each { |a|
|
95
|
+
#~ puts "#{a.name} == #{a.inspect_in_object(knxpacket, :default)}"
|
96
|
+
#~ }
|
97
|
+
#puts knxpacket.inspect_detailed
|
98
|
+
#~ require 'knx_tools'
|
99
|
+
#puts addr2str(knxpacket.src_addr)
|