OpenHAB

From MiOS
(Difference between revisions)
Jump to: navigation, search
(Creating an items file)
(Calculations)
 
(13 intermediate revisions by one user not shown)
Line 9: Line 9:
 
== Tools ==
 
== Tools ==
  
=== Creating an items file ===
+
=== Creating openHAB configuration files (items, sitemap, rrd4j persistence) ===
  
 +
Adjust unit_name and output_directory.
 +
 +
==== items ====
 
https://github.com/openhab/openhab/wiki/Explanation-of-items
 
https://github.com/openhab/openhab/wiki/Explanation-of-items
  
 +
Place *.items in: /openHAB/runtime/configurations/items
 +
 +
==== sitemap ====
 +
https://github.com/openhab/openhab/wiki/Explanation-of-Sitemaps
 +
 +
Place *.sitemap in: /openHAB/runtime/configurations/sitemaps
 +
 +
==== rrd4j persistence ====
 +
https://github.com/openhab/openhab/wiki/Persistence
 +
 +
[[Add]] rrd4j.persist_add to the Items section in /openHAB/runtime/configurations/persistence/rrd4j.persist and make sure that the strategies used are defined in the Strategies section.
 +
 +
==== Luup code for MiOS devices ====
 
<source lang="text">
 
<source lang="text">
  
local unit_name = 'house'
+
-- by Ap15e
 +
 
 +
local unit_name       = 'house'
 +
local output_directory = '/dataMine'
  
 
local device_types =
 
local device_types =
{ [ 'urn:schemas-upnp-org:device:DimmableLight:1'           ] = { 'Dimmer' , ' [%d]%'     , '<slider>'     , '/service/Dimming1/LoadLevelStatus,command:MAP(miosDimmerCommand.map)' },
+
{ [ 'urn:schemas-upnp-org:device:DimmableLight:1'                   ] = { 'Dimmer' , ' [%d]%'   , '<slider>'       , '/service/Dimming1/LoadLevelStatus,command:MAP(miosDimmerCommand.map)' },
   [ 'urn:schemas-upnp-org:device:BinaryLight:1'             ] = { 'Switch' , ''           , ''             , '/service/SwitchPower1/Status,command:ON=SwitchPower1/SetTarget(newTargetValue=1)|OFF=SwitchPower1/SetTarget(newTargetValue=0),in:MAP(miosSwitchIn.map)' },
+
   [ 'urn:schemas-upnp-org:device:BinaryLight:1'                     ] = { 'Switch' , ''         , ''               , '/service/SwitchPower1/Status,command:ON=SwitchPower1/SetTarget(newTargetValue=1)|OFF=SwitchPower1/SetTarget(newTargetValue=0),in:MAP(miosSwitchIn.map)' },
   [ 'urn:schemas-micasaverde-com:device:TemperatureSensor:1' ] = { 'Number' , ' [%.1f °C]' , '<temperature>', '/service/TemperatureSensor1/CurrentTemperature' },
+
   [ 'urn:schemas-micasaverde-com:device:TemperatureSensor:1'         ] = { 'Number' , ' [%.1f °C]', '<temperature>' , '/service/TemperatureSensor1/CurrentTemperature' },
   [ 'urn:schemas-micasaverde-com:device:HumiditySensor:1'   ] = { 'Number' , ' [%d]%'     , ''             , '/service/HumiditySensor1/CurrentLevel' },
+
   [ 'urn:schemas-micasaverde-com:device:HumiditySensor:1'           ] = { 'Number' , ' [%d]%'   , ''               , '/service/HumiditySensor1/CurrentLevel' },
   [ 'urn:schemas-micasaverde-com:device:MotionSensor:1'     ] = { 'Contact', ' [%s]'     , '<contact>'   , '/service/SecuritySensor1/Tripped,in:MAP(miosContactIn.map)' },
+
   [ 'urn:schemas-micasaverde-com:device:MotionSensor:1'             ] = { 'Contact', ' [%s]'     , '<contact>'     , '/service/SecuritySensor1/Tripped,in:MAP(miosContactIn.map)' },
   [ 'urn:schemas-micasaverde-com:device:LightSensor:1'       ] = { 'Number' , ' [%.2f]%'   , ''             , '/service/urn:micasaverde-com:serviceId:LightSensor1/CurrentLevel' },
+
   [ 'urn:schemas-micasaverde-com:device:LightSensor:1'               ] = { 'Number' , ' [%.2f]%' , ''               , '/service/urn:micasaverde-com:serviceId:LightSensor1/CurrentLevel' },
   [ 'urn:schemas-micasaverde-com:device:DoorSensor:1'       ] = { 'Contact', ' [%s]'     , '<contact>'   , '/service/SecuritySensor1/Tripped,in:MAP(miosContactIn.map)' },
+
   [ 'urn:schemas-micasaverde-com:device:DoorSensor:1'               ] = { 'Contact', ' [%s]'     , '<contact>'     , '/service/SecuritySensor1/Tripped,in:MAP(miosContactIn.map)' },
   [ 'urn:schemas-upnp-org:device:Heater:1'                   ] = { 'Number' , ' [%.1f °C]' , '<temperature>', '/service/urn:upnp-org:serviceId:TemperatureSetpoint1_Heat/CurrentSetpoint' },
+
   [ 'urn:schemas-upnp-org:device:Heater:1'                           ] = { 'Number' , ' [%.1f °C]', '<temperature>' , '/service/urn:upnp-org:serviceId:TemperatureSetpoint1_Heat/CurrentSetpoint' },
   [ 'urn:schemas-micasaverde-com:device:UvSensor:1'         ] = { 'Number' , ' [%d]'     , ''             , '/service/urn:upnp-org:serviceId:UvSensor1/CurrentLevel' },
+
   [ 'urn:schemas-micasaverde-com:device:UvSensor:1'                 ] = { 'Number' , ' [%d]'     , ''               , '/service/urn:upnp-org:serviceId:UvSensor1/CurrentLevel' },
   [ 'urn:schemas-micasaverde-com:device:RainSensor:1'       ] = { 'Number' , ' [%.1f]'   , ''             , '/service/urn:upnp-org:serviceId:RainSensor1/CurrentTRain' },
+
   [ 'urn:schemas-micasaverde-com:device:RainSensor:1'               ] = { 'Number' , ' [%.1f]'   , ''               , '/service/urn:upnp-org:serviceId:RainSensor1/CurrentTRain' },
   [ 'urn:schemas-micasaverde-com:device:ScaleSensor:1'       ] = { 'Number' , ' [%.1f]'   , ''             , '/service/urn:micasaverde-com:serviceId:ScaleSensor1/Weight' },
+
   [ 'urn:schemas-micasaverde-com:device:ScaleSensor:1'               ] = { 'Number' , ' [%.1f]'   , ''               , '/service/urn:micasaverde-com:serviceId:ScaleSensor1/Weight' },
   [ 'urn:schemas-micasaverde-com:device:BarometerSensor:1'   ] = { 'Number' , ' [%.2f]hPa' , ''             , '/service/urn:upnp-org:serviceId:BarometerSensor1/CurrentPressure' },
+
   [ 'urn:schemas-micasaverde-com:device:BarometerSensor:1'           ] = { 'Number' , ' [%.2f]hPa', ''               , '/service/urn:upnp-org:serviceId:BarometerSensor1/CurrentPressure' },
   [ 'urn:schemas-micasaverde-com:device:WindSensor:1'       ] = { 'Number' , ' [%.1f]'   , '<wind>'       , '/service/urn:upnp-org:serviceId:WindSensor1/AvgSpeed' },
+
   [ 'urn:schemas-micasaverde-com:device:WindSensor:1'               ] = { 'Number' , ' [%.1f]'   , '<wind>'         , '/service/urn:upnp-org:serviceId:WindSensor1/AvgSpeed' },
   [ 'urn:schemas-micasaverde-com:device:SmokeSensor:1'       ] = { 'Contact', ' [%s]'     , '<contact>'   , '/service/urn:upnp-org:serviceId:SmokeSensor1/Tripped,in:MAP(miosContactIn.map)' },
+
   [ 'urn:schemas-micasaverde-com:device:SmokeSensor:1'               ] = { 'Contact', ' [%s]'     , '<contact>'     , '/service/urn:upnp-org:serviceId:SmokeSensor1/Tripped,in:MAP(miosContactIn.map)' },
   [ 'urn:demo-micasaverde-com:device:weather:1'             ] = { 'String' , ' [%s]'     , ''             , '/service/urn:micasaverde-com:serviceId:Weather1/Condition' },
+
   [ 'urn:demo-micasaverde-com:device:weather:1'                     ] = { 'String' , ' [%s]'     , ''               , '/service/urn:micasaverde-com:serviceId:Weather1/Condition' },
   [ 'urn:schemas-ap15e-com:device:DAD'                       ] = { 'String' , ' [%s]'     , '<sun>'       , '/service/urn:upnp-ap15e-com:serviceId:DAD1/Sunrise_HHMMSS' },
+
   [ 'urn:schemas-ap15e-com:device:DAD'                               ] = { 'String' , ' [%s]'     , '<sun>'         , '/service/urn:upnp-ap15e-com:serviceId:DAD1/Sunrise_HHMMSS' },
   [ 'urn:schemas-micasaverde-com:device:WindowCovering:1'   ] = { 'Switch' , ''         , '<rollershutter>', '/service/SwitchPower1/Status,command:ON=SwitchPower1/SetTarget(newTargetValue=1)|OFF=SwitchPower1/SetTarget(newTargetValue=0),in:MAP(miosSwitchIn.map)' } }
+
   [ 'urn:schemas-micasaverde-com:device:WindowCovering:1'           ] = { 'Switch' , ''         , '<rollershutter>', '/service/SwitchPower1/Status,command:ON=SwitchPower1/SetTarget(newTargetValue=1)|OFF=SwitchPower1/SetTarget(newTargetValue=0),in:MAP(miosSwitchIn.map)' },
 +
  [ 'urn:schemas-futzle-com:device:CurrentCostEnviR:1'              ] = { 'Number' , ' [%d]'    , '<energy>'      , '/service/urn:micasaverde-com:serviceId:EnergyMetering1/Watts' },
 +
  [ 'urn:schemas-futzle-com:device:CurrentCostEnviRAppliancePhase:1' ] = { 'Number' , ' [%d]'    , '<energy>'      , '/service/urn:micasaverde-com:serviceId:EnergyMetering1/Watts' },
 +
  [ 'urn:schemas-futzle-com:device:CurrentCostEnviRAppliancePulse:1' ] = { 'Number' , ' [%d]'    , '<energy>'      , '/service/urn:micasaverde-com:serviceId:EnergyMetering1/Pulse' },
 +
  [ 'urn:schemas-futzle-com:device:holidayvirtualswitch:1'          ] = { 'Switch' , ''          , ''              , '/service/SwitchPower1/Status,command:ON=SwitchPower1/SetTarget(newTargetValue=1)|OFF=SwitchPower1/SetTarget(newTargetValue=0),in:MAP(miosSwitchIn.map)' } }
 +
 
 +
local device_categories = {
 +
[1] = { 'Interface' },
 +
[2] = { 'Dimmable Light' },
 +
[3] = { 'Switch', { [1] = 'Interior',
 +
                    [2] = 'Exterior',
 +
[3] = 'In Wall' ,
 +
                    [4] = 'Refrigerator',
 +
                    [5] = 'Garage Door' } },
 +
[4] = { 'Security Sensor', { [1] = 'Door Sensor',
 +
                            [2] = 'Leak Sensor',
 +
                            [3] = 'Motion Sensor',
 +
                            [4] = 'Smoke Sensor',
 +
                            [5] = 'CO Sensor',
 +
                            [6] = 'Glass Break Sensor' } },
 +
[5] = { 'HVAC', { [1] = 'HVAC',
 +
                  [2] = 'Heater' } },
 +
[6] = { 'Camera' },
 +
[7] = { 'Door Lock' },
 +
[8] = { 'Window Covering', { [1] = 'Window Covering',
 +
                            [2] = 'ZRTSI' } },
 +
[9] = { 'Remote Control' },
 +
[10] = { 'IR Transmitter', { [1] = 'IR Transmitter',
 +
                            [2] = 'USB UIRT' } },
 +
[11] = { 'Generic I/O' },
 +
[12] = { 'Generic Sensor' },
 +
[13] = { 'Serial Port' },
 +
[14] = { 'Scene Controller' },
 +
[15] = { 'A/V' },
 +
[16] = { 'Humidity Sensor' },
 +
[17] = { 'Temperature Sensor' },
 +
[18] = { 'Light Sensor' },
 +
[19] = { 'Z-Wave Interface' },
 +
[20] = { 'Insteon Interface' },
 +
[21] = { 'Power Meter' },
 +
[22] = { 'Alarm Panel' },
 +
[23] = { 'Alarm Partition' },
 +
[24] = { 'Siren' } }
 +
 
 +
group_written = {}
  
  
 
function normalize_name( s )
 
function normalize_name( s )
  
  s = string.gsub( s or '', '[%s-/%.:]', '_' )
+
  s = string.gsub( s or '', '[%s-/%.:()]', '_' )
 
  return '_' .. s
 
  return '_' .. s
  
 
end
 
end
  
luup.log( 'AAAGroup Rooms (All)' )
 
  
for k, v in pairs( device_types )
+
function write_items()
do
+
  
  t = string.match( k or '', '%:(%a*)%:1' )
+
outf = io.open( output_directory .. '/' .. unit_name .. '.items', 'w\n' )
  luup.log( 'AAAGroup _' .. tostring( t ) .. 's "' .. tostring( t ) .. 's" (Rooms)' )
+
  luup.log( 'AAANumber _' .. tostring( t ) .. 'sChartPeriod' )
+
  
  end
+
  outf:write( 'Group Rooms (All)\n' )
 +
 +
for k, v in pairs( luup.rooms )
 +
  do
  
for k, v in pairs( luup.rooms )
+
  outf:write( 'Group ' .. normalize_name( tostring( v ) ) .. ' "' .. tostring( v ) .. '" <' .. normalize_name( tostring( v ) ) .. '> (Rooms)\n' )
do
+
  
   luup.log( 'AAAGroup ' .. normalize_name( tostring( v ) ) .. ' "' .. tostring( v ) .. '" <' .. normalize_name( tostring( v ) ) .. '> (Rooms)' )
+
   end
  
  end
+
  outf:write( 'Group _no_room "no room" <_no_room> (Rooms)\n' )
  
luup.log( 'AAAGroup _nil "nil" <_nil> (Rooms)' )
+
for k, v in pairs(luup.devices)
 +
  do
  
for k, v in pairs(luup.devices) do
+
  dt = device_types[ v.device_type ]
  
dt = device_types[ v.device_type ]
+
  if dt ~= nil
 +
    then
  
  if dt ~= nil
+
    c = device_categories[ v.category_num ]
  then
+
  
  t = string.match( v.device_type or '', '%:(%a*)%:1' )
+
    if c == nil
 +
      then
  
  luup.log( 'AAA' .. tostring( dt[ 1 ] ) .. ' ' .. normalize_name( tostring( v.description ) ) .. ' "' .. tostring( v.description ) .. tostring( dt[ 2 ] ) .. '" ' .. tostring( dt[ 3 ] ) .. ' (' .. normalize_name( tostring( luup.rooms[ v.room_num ] ) ) .. ',_' .. tostring( t ) .. 's) {mios="unit:' .. tostring( unit_name ) .. ',device:' .. k .. tostring( dt[ 4 ] ) .. '"}' )
+
  t = 'DEVICE CATEGORY ' .. tostring( v.category_num ) .. '/' .. tostring( v.subcategory_num )
 +
 
 +
  else
 +
 
 +
        t  = c[ 1 ]
 +
 
 +
        st = c[ 2 ]
 +
 
 +
    if ( st ~= nil ) and ( v.subcategory_num ~= 0 )
 +
    then
 +
 
 +
      t =  t .. ' / ' .. tostring( st[ v.subcategory_num ] or v.subcategory_num )
 +
 
 +
    end
 +
 
 +
  end
 +
 
 +
    tn = normalize_name( t )
 +
 
 +
if group_written[ t ] == nil
 +
      then
 +
 
 +
  outf:write( 'Group ' .. tostring( tn ) .. 's "' .. tostring( t ) .. 's" (Rooms)\n' )
 +
      outf:write( 'Number ' .. tostring( tn ) .. 'sChartPeriod\n' )
 +
 
 +
  group_written[ t ] = tn
 +
 
 +
      end
 +
 
 +
    outf:write( tostring( dt[ 1 ] ) .. ' ' .. normalize_name( tostring( v.description ) ) .. ' "' .. tostring( v.description ) .. tostring( dt[ 2 ] ) .. '" ' .. tostring( dt[ 3 ] ) .. ' (' .. normalize_name( tostring( luup.rooms[ v.room_num ] ) ) .. ',' .. tostring( tn ) .. 's) {mios="unit:' .. tostring( unit_name ) .. ',device:' .. k .. tostring( dt[ 4 ] ) .. '"}\n' )
 +
 
 +
end
  
 
   end
 
   end
 +
 +
outf:close()
 +
 +
end -- function write_items()
 +
 +
 +
function write_sitemap()
 +
 +
outf = io.open( output_directory .. '/' .. unit_name .. '.sitemap', 'w\n' )
 +
 +
outf:write( 'sitemap ' .. unit_name .. ' label="Main Menu"\n' )
 +
outf:write( '{\n' )
 +
outf:write( ' Frame {\n' )
 +
outf:write( '        Group item=Rooms label="Rooms"\n' )
 +
outf:write( '      }\n' )
 +
 +
for k, v in pairs( group_written )
 +
  do
 +
 +
  p = tostring( v ) .. 'sChartPeriod'
 +
 +
  i = tostring( v ) .. 's'
 +
 +
  outf:write( ' Frame {\n' )
 +
  outf:write( '        Switch item=' .. p .. ' label="Chart Period" mappings=[0="Hour", 1="Day", 2="Week"]\n' )
 +
  outf:write( '        Chart item=' .. i .. ' period=h refresh=6000 visibility=[' .. p .. '==0, ' .. p .. '=="Uninitialized"]\n' )
 +
  outf:write( '        Chart item=' .. i .. ' period=D refresh=30000 visibility=[' .. p .. '==1]\n' )
 +
  outf:write( '        Chart item=' .. i .. ' period=W refresh=30000 visibility=[' .. p .. '==2]\n' )
 +
  outf:write( '      }\n' )
 +
 +
  end
 +
 +
outf:write( '}\n' )
 +
 +
outf:close()
 +
 +
end -- persistence_rrd4j()
 +
 +
 +
function write_persistence_rrd4j()
 +
 +
outf = io.open( output_directory .. '/rrd4j.persist_add', 'w' )
 +
 +
for k, v in pairs( group_written )
 +
  do
 +
 +
  i = tostring( v ) .. 's'
 +
 +
  outf:write( i .. '* : strategy = everyChange, everyMinute, restoreOnStartup\n' )
 +
 +
  end
 +
 +
outf:close()
 +
 +
end -- write_persistence_rrd4j()
 +
 +
 +
write_items()
 +
write_sitemap()
 +
write_persistence_rrd4j()
 +
 +
</source>
 +
 +
=== Creating openHAB rules ===
 +
 +
https://github.com/openhab/openhab/wiki/Rules
 +
 +
 +
[[WORK IN PROGRESS (non-functional demo)]]
 +
 +
Use a real computer to run the following code:
 +
 +
<source lang="text">
 +
-- by Ap15e
 +
 +
local json = require( 'dkjson' ) -- use a json parser that doesn't complain about empty arrays ...
 +
local http = require( 'socket.http' )
 +
 +
local url = 'http://192.168.178.116:3480/data_request?id=user_data'
 +
 +
function normalize_name( s )
 +
 +
s = string.gsub( s or '', '[%s-/%.:]', '_' )
 +
return '_' .. s
  
 
end
 
end
 +
 +
body, c, l, h = http.request( url )
 +
 +
print( '// status line', l )
 +
print( '// h', h )
 +
print( '// c', c )
 +
 +
print( '' )
 +
 +
if c == 200
 +
then
 +
 +
  local data = json.decode( body )
 +
 +
  for k, v in pairs( data.scenes )
 +
  do
 +
 +
    print( 'rule ' .. normalize_name( v.name ) )
 +
    print( '// MiOS id: ' .. v.id )
 +
    print( 'when' )
 +
 +
if v.timers ~= nil
 +
then
 +
 +
  for i, j in pairs( v.timers )
 +
  do
 +
 +
    t = tonumber( j.type )
 +
 +
    if t == 1
 +
                then
 +
 +
                  print( '  ', j.interval, '  // MiOS type 1' )
 +
 +
else if t == 2
 +
then
 +
 +
  print( '  ', j.days_of_week, j.time, '  // MiOS type 2' )
 +
 +
                else if t == 3
 +
                then
 +
 +
  print( '  ', '// ERROR: Not implemented - MiOS type 3' )
 +
 +
                else if t == 4
 +
                then
 +
 +
  print( '  ', j.abstime, '  // MiOS type 4' )
 +
 +
                else
 +
 +
  print( '// ERROR: unknown timer, MiOS type: ', tostring( t ) )
 +
 +
  for x, y in pairs( j )
 +
  do
 +
 +
    print( '//  ', x, y )
 +
 +
  end
 +
 +
end
 +
end
 +
end
 +
end
 +
 +
  end
 +
 +
end
 +
 +
if v.triggers ~= nil
 +
        then
 +
 +
  for i, j in pairs( v.triggers )
 +
  do
 +
 +
print( '// ' .. j.name )
 +
 +
for x, y in pairs( j )
 +
do
 +
  print( '    //', x, y )
 +
end
 +
 +
  end
 +
 +
end
 +
 +
    print( 'then' )
 +
    print( 'end' )
 +
    print( '' )
 +
 +
  end
 +
 +
else
 +
 +
  print( '//http error code:', c )
 +
 +
end
  
  
Line 87: Line 362:
  
 
Mount ~/openHAB/runtime/configurations/items on Vera (see http://forum.micasaverde.com/index.php/topic,16452.msg125963.html#msg125963) and write the items file via Apps -> Develop Apps -> Edit Startup Lua.
 
Mount ~/openHAB/runtime/configurations/items on Vera (see http://forum.micasaverde.com/index.php/topic,16452.msg125963.html#msg125963) and write the items file via Apps -> Develop Apps -> Edit Startup Lua.
 +
 +
=== Building a quarter wave ground plane antenna for Z-Wave ===
 +
 +
==== Parts needed ====
 +
 +
4x Amphenol B6351B1-ND3G-50
 +
 +
Copper wire
 +
 +
50 Ohm cable BNC male - BNC male
 +
 +
SMA male - BNC female adapter (for Vera3 with antenna mod)
 +
 +
U.FL female - BNC female pigtail cable and U.FL male coaxial connector SMD (for Aeon Z-Stick S2)
 +
 +
[[File:parts.jpg|400px]]
 +
 +
==== Calculations ====
 +
 +
length of radials/radiator = speed of light / frequency * velocity factor / 4
 +
 +
For EU frequency: length = 299792458 m/s / 868420000 Hz * 0.95 / 4 = 8.2 cm
 +
 +
==== Antenna ====
 +
 +
[[File:antenna.jpg|200px]]
 +
 +
==== Modifying the Aeon Z-Stick S2 ====
 +
 +
[[File:z_stick_s2.jpg|400px]]
 +
 +
== Screenshots ==
 +
 +
[[File:openHAB1.jpg|300px]] [[File:openHAB2.jpg|300px]] [[File:openHAB3.jpg|300px]]

Latest revision as of 20:46, 26 January 2015

Contents

[edit] openHAB Downloads

http://www.openhab.org/downloads.html

[edit] openHAB MiOS binding

https://github.com/openhab/openhab/tree/master/bundles/binding/org.openhab.binding.mios

[edit] Tools

[edit] Creating openHAB configuration files (items, sitemap, rrd4j persistence)

Adjust unit_name and output_directory.

[edit] items

https://github.com/openhab/openhab/wiki/Explanation-of-items

Place *.items in: /openHAB/runtime/configurations/items

[edit] sitemap

https://github.com/openhab/openhab/wiki/Explanation-of-Sitemaps

Place *.sitemap in: /openHAB/runtime/configurations/sitemaps

[edit] rrd4j persistence

https://github.com/openhab/openhab/wiki/Persistence

Add rrd4j.persist_add to the Items section in /openHAB/runtime/configurations/persistence/rrd4j.persist and make sure that the strategies used are defined in the Strategies section.

[edit] Luup code for MiOS devices

-- by Ap15e
 
local unit_name        = 'house'
local output_directory = '/dataMine'
 
local device_types =
{ [ 'urn:schemas-upnp-org:device:DimmableLight:1'                    ] = { 'Dimmer' , ' [%d]%'    , '<slider>'       , '/service/Dimming1/LoadLevelStatus,command:MAP(miosDimmerCommand.map)' },
  [ 'urn:schemas-upnp-org:device:BinaryLight:1'                      ] = { 'Switch' , ''          , ''               , '/service/SwitchPower1/Status,command:ON=SwitchPower1/SetTarget(newTargetValue=1)|OFF=SwitchPower1/SetTarget(newTargetValue=0),in:MAP(miosSwitchIn.map)' },
  [ 'urn:schemas-micasaverde-com:device:TemperatureSensor:1'         ] = { 'Number' , ' [%.1f °C]', '<temperature>'  , '/service/TemperatureSensor1/CurrentTemperature' },
  [ 'urn:schemas-micasaverde-com:device:HumiditySensor:1'            ] = { 'Number' , ' [%d]%'    , ''               , '/service/HumiditySensor1/CurrentLevel' },
  [ 'urn:schemas-micasaverde-com:device:MotionSensor:1'              ] = { 'Contact', ' [%s]'     , '<contact>'      , '/service/SecuritySensor1/Tripped,in:MAP(miosContactIn.map)' },
  [ 'urn:schemas-micasaverde-com:device:LightSensor:1'               ] = { 'Number' , ' [%.2f]%'  , ''               , '/service/urn:micasaverde-com:serviceId:LightSensor1/CurrentLevel' },
  [ 'urn:schemas-micasaverde-com:device:DoorSensor:1'                ] = { 'Contact', ' [%s]'     , '<contact>'      , '/service/SecuritySensor1/Tripped,in:MAP(miosContactIn.map)' },
  [ 'urn:schemas-upnp-org:device:Heater:1'                           ] = { 'Number' , ' [%.1f °C]', '<temperature>'  , '/service/urn:upnp-org:serviceId:TemperatureSetpoint1_Heat/CurrentSetpoint' },
  [ 'urn:schemas-micasaverde-com:device:UvSensor:1'                  ] = { 'Number' , ' [%d]'     , ''               , '/service/urn:upnp-org:serviceId:UvSensor1/CurrentLevel' },
  [ 'urn:schemas-micasaverde-com:device:RainSensor:1'                ] = { 'Number' , ' [%.1f]'   , ''               , '/service/urn:upnp-org:serviceId:RainSensor1/CurrentTRain' },
  [ 'urn:schemas-micasaverde-com:device:ScaleSensor:1'               ] = { 'Number' , ' [%.1f]'   , ''               , '/service/urn:micasaverde-com:serviceId:ScaleSensor1/Weight' },
  [ 'urn:schemas-micasaverde-com:device:BarometerSensor:1'           ] = { 'Number' , ' [%.2f]hPa', ''               , '/service/urn:upnp-org:serviceId:BarometerSensor1/CurrentPressure' },
  [ 'urn:schemas-micasaverde-com:device:WindSensor:1'                ] = { 'Number' , ' [%.1f]'   , '<wind>'         , '/service/urn:upnp-org:serviceId:WindSensor1/AvgSpeed' },
  [ 'urn:schemas-micasaverde-com:device:SmokeSensor:1'               ] = { 'Contact', ' [%s]'     , '<contact>'      , '/service/urn:upnp-org:serviceId:SmokeSensor1/Tripped,in:MAP(miosContactIn.map)' },
  [ 'urn:demo-micasaverde-com:device:weather:1'                      ] = { 'String' , ' [%s]'     , ''               , '/service/urn:micasaverde-com:serviceId:Weather1/Condition' },
  [ 'urn:schemas-ap15e-com:device:DAD'                               ] = { 'String' , ' [%s]'     , '<sun>'          , '/service/urn:upnp-ap15e-com:serviceId:DAD1/Sunrise_HHMMSS' },
  [ 'urn:schemas-micasaverde-com:device:WindowCovering:1'            ] = { 'Switch' , ''          , '<rollershutter>', '/service/SwitchPower1/Status,command:ON=SwitchPower1/SetTarget(newTargetValue=1)|OFF=SwitchPower1/SetTarget(newTargetValue=0),in:MAP(miosSwitchIn.map)' },
  [ 'urn:schemas-futzle-com:device:CurrentCostEnviR:1'               ] = { 'Number' , ' [%d]'     , '<energy>'       , '/service/urn:micasaverde-com:serviceId:EnergyMetering1/Watts' },
  [ 'urn:schemas-futzle-com:device:CurrentCostEnviRAppliancePhase:1' ] = { 'Number' , ' [%d]'     , '<energy>'       , '/service/urn:micasaverde-com:serviceId:EnergyMetering1/Watts' },
  [ 'urn:schemas-futzle-com:device:CurrentCostEnviRAppliancePulse:1' ] = { 'Number' , ' [%d]'     , '<energy>'       , '/service/urn:micasaverde-com:serviceId:EnergyMetering1/Pulse' },
  [ 'urn:schemas-futzle-com:device:holidayvirtualswitch:1'           ] = { 'Switch' , ''          , ''               , '/service/SwitchPower1/Status,command:ON=SwitchPower1/SetTarget(newTargetValue=1)|OFF=SwitchPower1/SetTarget(newTargetValue=0),in:MAP(miosSwitchIn.map)' } }
 
local device_categories = {
[1] = { 'Interface' },
[2] = { 'Dimmable Light' },
[3] = { 'Switch', { [1] = 'Interior',
                    [2] = 'Exterior',
					[3] = 'In Wall' ,
                    [4] = 'Refrigerator',
                    [5] = 'Garage Door' } },
[4] = {	'Security Sensor', { [1] = 'Door Sensor',
                             [2] = 'Leak Sensor',
                             [3] = 'Motion Sensor',
                             [4] = 'Smoke Sensor',
                             [5] = 'CO Sensor',
                             [6] = 'Glass Break Sensor' } },
[5] = { 'HVAC', { [1] =	'HVAC',
                  [2] = 'Heater' } },
[6] = { 'Camera' },
[7] = { 'Door Lock' },
[8] = { 'Window Covering', { [1] = 'Window Covering',
                            [2] = 'ZRTSI' } },
[9] = { 'Remote Control' },
[10] = { 'IR Transmitter', { [1] = 'IR Transmitter',
                             [2] = 'USB UIRT' } },
[11] = { 'Generic I/O' },
[12] = { 'Generic Sensor' },
[13] = { 'Serial Port' },
[14] = { 'Scene Controller' },
[15] = { 'A/V' },
[16] = { 'Humidity Sensor' },
[17] = { 'Temperature Sensor' },
[18] = { 'Light Sensor' },
[19] = { 'Z-Wave Interface' },
[20] = { 'Insteon Interface' },
[21] = { 'Power Meter' },
[22] = { 'Alarm Panel' },
[23] = { 'Alarm Partition' },
[24] = { 'Siren' } }
 
group_written = {}
 
 
function normalize_name( s )
 
 s = string.gsub( s or '', '[%s-/%.:()]', '_' )
 return '_' .. s
 
end
 
 
function write_items()
 
 outf = io.open( output_directory .. '/' .. unit_name .. '.items', 'w\n' )
 
 outf:write( 'Group Rooms (All)\n' )
 
 for k, v in pairs( luup.rooms )
  do
 
   outf:write( 'Group ' .. normalize_name( tostring( v ) ) .. ' "' .. tostring( v ) .. '" <' .. normalize_name( tostring( v ) ) .. '> (Rooms)\n' )
 
  end
 
 outf:write( 'Group _no_room "no room" <_no_room> (Rooms)\n' )
 
 for k, v in pairs(luup.devices)
  do
 
   dt = device_types[ v.device_type ]
 
   if dt ~= nil
    then
 
     c  = device_categories[ v.category_num ]
 
     if c == nil
      then
 
	   t = 'DEVICE CATEGORY ' .. tostring( v.category_num ) .. '/' .. tostring( v.subcategory_num )
 
	  else
 
        t  = c[ 1 ]
 
        st = c[ 2 ]
 
	    if ( st ~= nil ) and ( v.subcategory_num ~= 0 )
	     then
 
	      t =  t .. ' / ' .. tostring( st[ v.subcategory_num ] or v.subcategory_num )
 
	     end
 
	  end
 
     tn = normalize_name( t )
 
	 if group_written[ t ] == nil
      then
 
	   outf:write( 'Group ' .. tostring( tn ) .. 's "' .. tostring( t ) .. 's" (Rooms)\n' )
       outf:write( 'Number ' .. tostring( tn ) .. 'sChartPeriod\n' )
 
	   group_written[ t ] = tn
 
      end
 
     outf:write( tostring( dt[ 1 ] ) .. ' ' .. normalize_name( tostring( v.description ) ) .. ' "' .. tostring( v.description ) .. tostring( dt[ 2 ] ) .. '" ' .. tostring( dt[ 3 ] ) .. ' (' .. normalize_name( tostring( luup.rooms[ v.room_num ] ) ) .. ',' .. tostring( tn ) .. 's) {mios="unit:' .. tostring( unit_name ) .. ',device:' .. k .. tostring( dt[ 4 ] ) .. '"}\n' )
 
	end
 
  end
 
 outf:close()
 
end -- function write_items()
 
 
function write_sitemap()
 
 outf = io.open( output_directory .. '/' .. unit_name .. '.sitemap', 'w\n' )
 
 outf:write( 'sitemap ' .. unit_name .. ' label="Main Menu"\n' )
 outf:write( '{\n' )
 outf:write( ' Frame {\n' )
 outf:write( '        Group item=Rooms label="Rooms"\n' )
 outf:write( '       }\n' )
 
 for k, v in pairs( group_written )
  do
 
   p = tostring( v ) .. 'sChartPeriod'
 
   i = tostring( v ) .. 's'
 
   outf:write( ' Frame {\n' )
   outf:write( '        Switch item=' .. p .. ' label="Chart Period" mappings=[0="Hour", 1="Day", 2="Week"]\n' )
   outf:write( '        Chart item=' .. i .. ' period=h refresh=6000 visibility=[' .. p .. '==0, ' .. p .. '=="Uninitialized"]\n' )
   outf:write( '        Chart item=' .. i .. ' period=D refresh=30000 visibility=[' .. p .. '==1]\n' )
   outf:write( '        Chart item=' .. i .. ' period=W refresh=30000 visibility=[' .. p .. '==2]\n' )
   outf:write( '       }\n' )
 
  end
 
 outf:write( '}\n' )
 
 outf:close()
 
end -- persistence_rrd4j()
 
 
function write_persistence_rrd4j()
 
 outf = io.open( output_directory .. '/rrd4j.persist_add', 'w' )
 
 for k, v in pairs( group_written )
  do
 
   i = tostring( v ) .. 's'
 
   outf:write( i .. '* : strategy = everyChange, everyMinute, restoreOnStartup\n' )
 
  end
 
 outf:close()
 
end -- write_persistence_rrd4j()
 
 
write_items()
write_sitemap()
write_persistence_rrd4j()

[edit] Creating openHAB rules

https://github.com/openhab/openhab/wiki/Rules


WORK IN PROGRESS (non-functional demo)

Use a real computer to run the following code:

-- by Ap15e
 
local json = require( 'dkjson' ) -- use a json parser that doesn't complain about empty arrays ...
local http = require( 'socket.http' )
 
local url = 'http://192.168.178.116:3480/data_request?id=user_data'
 
function normalize_name( s )
 
 s = string.gsub( s or '', '[%s-/%.:]', '_' )
 return '_' .. s
 
end
 
body, c, l, h = http.request( url )
 
print( '// status line', l )
print( '// h', h )
print( '// c', c )
 
print( '' )
 
if c == 200
 then
 
  local data = json.decode( body )
 
  for k, v in pairs( data.scenes )
   do
 
    print( 'rule ' .. normalize_name( v.name ) )
    print( '// MiOS id: ' .. v.id )
    print( 'when' )
 
	if v.timers ~= nil
	 then
 
	  for i, j in pairs( v.timers )
	   do
 
	    t = tonumber( j.type )
 
	    if t == 1
                then
 
                  print( '  ', j.interval, '  // MiOS type 1' )
 
		else if t == 2
		 then
 
		  print( '  ', j.days_of_week, j.time, '  // MiOS type 2' )
 
                else if t == 3
                 then
 
 		  print( '  ', '// ERROR: Not implemented - MiOS type 3' )
 
                else if t == 4
                 then
 
 		  print( '  ', j.abstime, '  // MiOS type 4' )
 
                 else
 
		  print( '// ERROR: unknown timer, MiOS type: ', tostring( t ) )
 
		  for x, y in pairs( j )
		   do
 
		    print( '//  ', x, y )
 
		   end
 
		 end
		 end
		 end
		 end
 
	   end
 
	 end
 
	if v.triggers ~= nil
         then
 
	  for i, j in pairs( v.triggers )
	   do
 
		print( '// ' .. j.name )
 
		for x, y in pairs( j )
		 do
		  print( '    //', x, y )
		 end
 
	   end
 
	 end
 
    print( 'then' )
    print( 'end' )
    print( '' )
 
   end
 
 else
 
  print( '//http error code:', c )
 
 end

[edit] Tips & Tricks

[edit] Synchronizing Vera's devices with openHAB

Mount ~/openHAB/runtime/configurations/items on Vera (see http://forum.micasaverde.com/index.php/topic,16452.msg125963.html#msg125963) and write the items file via Apps -> Develop Apps -> Edit Startup Lua.

[edit] Building a quarter wave ground plane antenna for Z-Wave

[edit] Parts needed

4x Amphenol B6351B1-ND3G-50

Copper wire

50 Ohm cable BNC male - BNC male

SMA male - BNC female adapter (for Vera3 with antenna mod)

U.FL female - BNC female pigtail cable and U.FL male coaxial connector SMD (for Aeon Z-Stick S2)

Parts.jpg

[edit] Calculations

length of radials/radiator = speed of light / frequency * velocity factor / 4

For EU frequency: length = 299792458 m/s / 868420000 Hz * 0.95 / 4 = 8.2 cm

[edit] Antenna

Antenna.jpg

[edit] Modifying the Aeon Z-Stick S2

Z stick s2.jpg

[edit] Screenshots

OpenHAB1.jpg OpenHAB2.jpg OpenHAB3.jpg

Personal tools