Changes in / [1:3]


Ignore:
Location:
/trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • /trunk/D_OpenThermGateway.json

    r1 r3  
    3535            "FanMode": { 
    3636                "Style": "numeric", 
    37                 "Service": "urn: upnp-org: serviceId: HVAC_FanOperatingMode1", 
     37                "Service": "urn:upnp-org:serviceId:HVAC_FanOperatingMode1", 
    3838                "Variable": "ModeStatus" 
    3939            } 
     
    170170                    }, 
    171171                    "ControlCode": "heater_setpoint" 
     172                }, 
     173                { 
     174                    "ControlType": "label", 
     175                    "Label": { 
     176                        "lang_tag": "firmware", 
     177                        "text": "Gateway firmware version:" 
     178                    }, 
     179                    "Display": { 
     180                        "Top": 140, 
     181                        "Left": 50, 
     182                        "Width": 75, 
     183                        "Height": 20 
     184                    } 
     185                }, 
     186                { 
     187                    "ControlType": "variable", 
     188                    "Display": { 
     189                        "Service": "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", 
     190                        "Variable": "FirmwareVersion", 
     191                        "Top": 140, 
     192                        "Left": 200, 
     193                        "Width": 175, 
     194                        "Height": 20 
     195                    } 
     196                }, 
     197                { 
     198                    "ControlType": "label", 
     199                    "Label": { 
     200                        "lang_tag": "cmd", 
     201                        "text": "Free format command:" 
     202                    }, 
     203                    "Display": { 
     204                        "Top": 220, 
     205                        "Left": 50, 
     206                        "Width": 75, 
     207                        "Height": 20 
     208                    } 
     209                }, 
     210                { 
     211                    "ControlType":"input", 
     212                    "ID": "CustomCommand", 
     213                    "Style":"text", 
     214                    "Display":{ 
     215                        "Top": 217, 
     216                        "Left": 200, 
     217                        "Width": 100, 
     218                        "Height": 20 
     219                    } 
     220                }, 
     221                { 
     222                    "ControlType": "button", 
     223                    "Label": { 
     224                        "lang_tag": "cmd_send", 
     225                        "text": "Send" 
     226                    }, 
     227                    "Display": { 
     228                        "Top": 217, 
     229                        "Left": 325, 
     230                        "Width": 75, 
     231                        "Height": 20, 
     232                        "Service": "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", 
     233                    }, 
     234                    "Command": { 
     235                        "Service": "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", 
     236                        "Action": "SendCommand", 
     237                        "Parameters": [ 
     238                            { 
     239                                "Name": "Command", 
     240                                "ID": "CustomCommand" 
     241                            } 
     242                        ] 
     243                    }, 
     244                    "ControlCode": "heater_cmd" 
     245                }, 
     246                { 
     247                    "ControlType": "variable", 
     248                    "Display": { 
     249                        "Service": "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", 
     250                        "Variable": "CommandResponse", 
     251                        "Top": 220, 
     252                        "Left": 425, 
     253                        "Width": 175, 
     254                        "Height": 20 
     255                    } 
    172256                } 
    173257            ] 
     
    363447        } 
    364448    ], 
    365     "DeviceType": "urn:schemas-upnp-org:device:Heater:1" 
     449    "DeviceType": "urn:schemas-upnp-org:device:HVAC_ZoneThermostat:1" 
    366450} 
  • /trunk/S_OpenThermGateway.xml

    r1 r3  
    33  <specVersion> 
    44    <major>1</major> 
    5     <minor>0</minor> 
     5    <minor>1</minor> 
    66  </specVersion> 
    77  <serviceStateTable> 
     
    1717    </stateVariable> 
    1818  </serviceStateTable> 
    19  <actionList> 
    20   </actionList> 
     19  <actionList> 
     20    <action> 
     21      <name>SetOutsideTemperature</name> 
     22      <argumentList> 
     23        <argument> 
     24          <name>NewTemperature</name> 
     25          <direction>in</direction> 
     26        </argument> 
     27      </argumentList> 
     28    </action> 
     29     <action> 
     30      <name>SendCommand</name> 
     31      <argumentList> 
     32        <argument> 
     33          <name>Command</name> 
     34          <direction>in</direction> 
     35        </argument> 
     36      </argumentList> 
     37    </action> 
     38 </actionList> 
    2139</scpd> 
  • /trunk/D_OpenThermGateway.xml

    r1 r3  
    77  <device> 
    88    <deviceType>urn:schemas-upnp-org:device:HVAC_ZoneThermostat:1</deviceType> 
    9     <Category_Num>5</Category_Num> 
    10     <SubCategory_Num>2</SubCategory_Num> 
    119    <staticJson>D_OpenThermGateway.json</staticJson> 
    1210    <serviceList> 
     
    1715      </service> 
    1816      <service> 
    19       <Optional/> 
    20          <serviceType>urn:schemas-upnp-org:service:Heater:1</serviceType> 
    21          <serviceId>urn:schemas-upnp-org:serviceId:Heater1</serviceId> 
    22          <SCPDURL>D_Heater1.xml</SCPDURL> 
     17        <Optional/> 
     18        <serviceType>urn:schemas-upnp-org:service:HVAC_FanOperatingMode:1</serviceType> 
     19        <serviceId>urn:upnp-org:serviceId:HVAC_FanOperatingMode1</serviceId> 
     20        <SCPDURL>S_HVAC_FanOperatingMode1.xml</SCPDURL> 
     21      </service> 
     22      <service> 
     23        <serviceType>urn:micasaverde-com:serviceId:HVAC_OperatingState:1</serviceType> 
     24        <serviceId>urn:micasaverde-com:serviceId:HVAC_OperatingState1</serviceId> 
     25        <SCPDURL>S_HVAC_OperatingState1.xml</SCPDURL> 
     26      </service> 
     27      <service> 
     28        <serviceType>urn:schemas-upnp-org:service:HVAC_UserOperatingMode:1</serviceType> 
     29        <serviceId>urn:upnp-org:serviceId:HVAC_UserOperatingMode1</serviceId> 
     30        <SCPDURL>S_HVAC_UserOperatingMode1.xml</SCPDURL> 
     31      </service> 
     32      <service> 
     33        <Optional/> 
     34        <serviceType>urn:schemas-upnp-org:service:FanSpeed:1</serviceType> 
     35        <serviceId>urn:upnp-org:serviceId:FanSpeed1</serviceId> 
     36        <SCPDURL>S_FanSpeed1.xml</SCPDURL> 
     37      </service> 
     38      <service> 
     39        <serviceType>urn:schemas-upnp-org:service:TemperatureSensor:1</serviceType> 
     40        <serviceId>urn:upnp-org:serviceId:TemperatureSensor1</serviceId> 
     41        <SCPDURL>S_TemperatureSensor1.xml</SCPDURL> 
     42      </service> 
     43      <service> 
     44        <serviceType>urn:schemas-upnp-org:service:TemperatureSetpoint:1</serviceType> 
     45        <serviceId>urn:upnp-org:serviceId:TemperatureSetpoint1_Heat</serviceId> 
     46        <SCPDURL>S_TemperatureSetpoint1.xml</SCPDURL> 
     47      </service> 
     48      <service> 
     49        <serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType> 
     50        <serviceId>urn:upnp-org:serviceId:SwitchPower1</serviceId> 
     51        <SCPDURL>S_SwitchPower1.xml</SCPDURL> 
     52      </service> 
     53      <service> 
     54        <serviceType>urn:schemas-micasaverde-com:service:EnergyMetering:1</serviceType> 
     55        <serviceId>urn:micasaverde-com:serviceId:EnergyMetering1</serviceId> 
     56        <SCPDURL>S_EnergyMetering1.xml</SCPDURL> 
     57      </service> 
     58      <service> 
     59        <serviceType>urn:schemas-micasaverde-com:service:HaDevice:1</serviceType> 
     60        <serviceId>urn:micasaverde-com:serviceId:HaDevice1</serviceId> 
     61        <SCPDURL>S_HaDevice1.xml</SCPDURL> 
    2362      </service> 
    2463    </serviceList> 
  • /trunk/J_OpenThermGateway.js

    r1 r3  
    11var browserIE = false; 
    22var otgjsButtons = new Array(); 
     3var otgjsMessage; 
    34var otgjsConfig; 
    45 
    56// Flag ID, y, x1, x2 
    67var otgjsInfoFlagLayout = [ 
    7    [0x0100,  20,  30, 190], 
    8    [0x0200,  40,  30, 190], 
    9    [0x0400,  60,  30, 190], 
    10    [0x0800,  80,  30, 190], 
    11    [0x1000, 100,  30, 190], 
    12    [0x0001,  20, 230, 385], 
    13    [0x0002,  40, 230, 385], 
    14    [0x0004,  60, 230, 385], 
    15    [0x0008,  80, 230, 385], 
    16    [0x0010, 100, 230, 385], 
    17    [0x0020, 120,  30, 190], 
    18    [0x0040, 120, 230, 385] 
     8   [0x0100,  20,  30, 190], // Central Heating enable 
     9   [0x0200,  40,  30, 190], // Domestic Hot Water enable 
     10   [0x0400,  60,  30, 190], // Cooling enable 
     11   [0x0800,  80,  30, 190], // OTC active 
     12   [0x1000, 100,  30, 190], // Central Heating 2 enable 
     13   [0x0001, 120,  30, 190], // Fault indication 
     14   [0x0002,  20, 235, 390], // Central Heating mode 
     15   [0x0004,  40, 235, 390], // Domestic Hot Water mode 
     16   [0x0008,  80, 235, 390], // Flame status 
     17   [0x0010,  60, 235, 390], // Cooling status 
     18   [0x0020, 100, 235, 390], // Central Heating 2 mode 
     19   [0x0040, 120, 235, 390]  // Diagnostic indication 
    1920] 
    2021 
    2122// Fault ID, y, x1, x2 
    2223var otgjsInfoFaultLayout = [ 
    23    [0x0100,  20, 425, 570], 
    24    [0x0200,  40, 425, 570], 
    25    [0x0400,  60, 425, 570], 
    26    [0x0800,  80, 425, 570], 
    27    [0x1000, 100, 425, 570], 
    28    [0x2000, 120, 425, 570] 
     24   [0x0100,  20, 435, 580], 
     25   [0x0200,  40, 435, 580], 
     26   [0x0400,  60, 435, 580], 
     27   [0x0800,  80, 435, 580], 
     28   [0x1000, 100, 435, 580], 
     29   [0x2000, 120, 435, 580] 
    2930] 
    3031 
    31 // Message ID, y, x1, x2 
     32// Message ID, y, x1, x2, optional: index hb/lb 
    3233var otgjsInfoMsgLayout = [ 
    33    [24, 160,  30, 215], 
    34    [16, 160, 330, 535], 
    35    [25, 180,  30, 215], 
    36    [28, 200,  30, 215], 
    37    [17, 180, 330, 535], 
    38    [14, 200, 330, 535], 
    39    [27, 220,  30, 215], 
    40    [ 1, 220, 330, 535], 
    41    [26, 240,  30, 215], 
    42    [56, 240, 330, 535] 
     34   [ 1, 215, 340, 540], // Control setpoint 
     35   [ 5, 275, 340, 540, 'lb'], // Fault flags & OEM fault code 
     36   [ 9, 175, 340, 540], // Remote override room setpoint 
     37   [14, 255, 340, 540], // Maximum relative modulation level 
     38   [16, 155, 340, 540], // Room setpoint 
     39   [17, 255,  30, 220], // Relative modulation level 
     40   [18, 275,  30, 220], // Central heating water pressure 
     41   [24, 155,  30, 220], // Room temperature 
     42   [25, 175,  30, 220], // Boiler water temperature 
     43   [26, 235,  30, 220], // DHW temperature 
     44   [27, 215,  30, 220], // Outside temperature 
     45   [28, 195,  30, 220], // Return water temperature 
     46   [56, 235, 340, 540], // DHW setpoint 
     47   [57, 195, 340, 540]  // Max CH water setpoint 
    4348]; 
    4449 
     
    4752 
    4853function otgjsInfoTab(deviceID) { 
    49    var html = '<style type="text/css">input {margin:0px;} .skinned-form-controls input[type="checkbox"]:disabled + span, .skinned-form-controls input[type="checkbox"]:disabled + span:before {opacity: 1.0;}</style>'; 
    50  
     54   var html = '<style type="text/css">input {margin:0px;} .skinned-form-controls input[type="checkbox"]:disabled + span, .skinned-form-controls input[type="checkbox"]:disabled + span:before {opacity: 1.0;} ' 
     55   html += 'div.hr {height: 1px; background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(200,200,200,0.9), rgba(0,0,0,0)); ';  
     56   html += 'background-image:    -moz-linear-gradient(left, rgba(0,0,0,0), rgba(200,200,200,0.75), rgba(0,0,0,0)); ';  
     57   html += 'background-image:     -ms-linear-gradient(left, rgba(0,0,0,0), rgba(200,200,200,0.9), rgba(0,0,0,0)); ';  
     58   html += 'background-image:      -o-linear-gradient(left, rgba(0,0,0,0), rgba(200,200,200,0.9), rgba(0,0,0,0));} '; 
     59   html += 'div.err {color: #ABABAB}</style>'; 
    5160   for (var i=0; i<otgjsInfoFlagLayout.length; i++) { 
    5261      html += '<div class="label" id="flag'+otgjsInfoFlagLayout[i][0]+'" style="position: absolute; top: '+otgjsInfoFlagLayout[i][1]+'px; left: '+otgjsInfoFlagLayout[i][2]+'px;"></div>'; 
     
    5968      html += '<input type="checkbox" id="faultcheck'+otgjsInfoFaultLayout[i][0]+'" disabled><span></span></div>'; 
    6069   } 
     70   html += '<div class="hr" style="position: absolute; top: 145px; left: 28px; width: 570px;"></div>'; 
    6171   for (var i=0; i<otgjsInfoMsgLayout.length; i++) { 
    62       html += '<div class="label" id="msg'+otgjsInfoMsgLayout[i][0]+'" style="position: absolute; top: '+otgjsInfoMsgLayout[i][1]+'px; left: '+otgjsInfoMsgLayout[i][2]+'px;">' 
    63       html += '</div><div class="variable" id="msgval'+otgjsInfoMsgLayout[i][0]+'" style="position: absolute; top: '+otgjsInfoMsgLayout[i][1]+'px; left: '+otgjsInfoMsgLayout[i][3]+'px; width: 50px; text-align: right"></div>' 
    64    } 
    65  
     72      html += '<div class="label" id="msg'+otgjsInfoMsgLayout[i][0]+'" style="position: absolute; top: '+otgjsInfoMsgLayout[i][1]+'px; left: '+otgjsInfoMsgLayout[i][2]+'px;">'; 
     73      html += '</div><div class="variable" id="msgval'+otgjsInfoMsgLayout[i][0]+'" style="position: absolute; top: '+otgjsInfoMsgLayout[i][1]+'px; left: '+otgjsInfoMsgLayout[i][3]+'px; width: 55px; text-align: right"></div>'; 
     74   } 
     75   html += '<div class="hr" style="position: absolute; top: 300px; left: 28px; width: 570px;"></div>'; 
     76   for (var i=0; i<4; i++) { 
     77      html += '<div class="err" id="err'+i+'" style="position: absolute; top: 310px; left: '+(50+145*i)+'px;">'; 
     78      html += '</div><div class="err" id="errval'+i+'" style="position: absolute; top: 310px; left: '+(100+145*i)+'px; width: 30px; text-align: right"></div>'; 
     79   } 
    6680   otgjsDetectBrowser(); 
    6781   set_panel_html(html); 
    68    otgjsGetInfo(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", 'GetConfiguration', otgjsInfoConfig); 
     82   if (otgjsMessage == undefined) { 
     83      otgjsGetInfo(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", 'GetMessages', otgjsInfoConfig); 
     84   } else { 
     85      otgjsInfoConfig(deviceID, otgjsMessage); 
     86   } 
     87} 
     88 
     89function otgjsGetVariableState(deviceObj, service, variable) { 
     90   if (deviceObj && deviceObj.states) { 
     91      var statesNo = deviceObj.states.length; 
     92      for (var i=0; i<statesNo; i++) { 
     93         var stateObj = deviceObj.states[i]; 
     94         if(stateObj && stateObj.service == service && stateObj.variable == variable) { 
     95            return stateObj.value; 
     96         } 
     97      } 
     98   } 
     99   return undefined 
    69100} 
    70101 
     
    72103   // Keep updating while we are on this tab 
    73104   if (document.getElementById('msg'+otgjsInfoMsgLayout[0][0]) != null) { 
     105      // Get the state of the device 
     106      var deviceObj = get_lu_status_device_obj(deviceID); 
    74107      // Update flag values 
    75108      for (var i=0; i<otgjsInfoFlagLayout.length; i++) { 
    76109         var elem = document.getElementById('flagcheck'+otgjsInfoFlagLayout[i][0]); 
    77          var msg = otgjsConfig[0].flags[otgjsInfoFlagLayout[i][0]]; 
    78          var val = get_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", msg.var, 1); 
     110         var msg = otgjsMessage[0].flags[otgjsInfoFlagLayout[i][0]]; 
     111         var val = otgjsGetVariableState(deviceObj, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", msg.var); 
    79112         elem.checked = (val == "1"); 
    80113      } 
     
    82115      for (var i=0; i<otgjsInfoFaultLayout.length; i++) { 
    83116         var elem = document.getElementById('faultcheck'+otgjsInfoFaultLayout[i][0]); 
    84          var msg = otgjsConfig[5].flags[otgjsInfoFaultLayout[i][0]]; 
    85          var val = get_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", msg.var, 1); 
     117         var msg = otgjsMessage[5].flags[otgjsInfoFaultLayout[i][0]]; 
     118         var val = otgjsGetVariableState(deviceObj, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", msg.var); 
    86119         elem.checked = (val == "1"); 
    87120      } 
     
    89122      for (var i=0; i<otgjsInfoMsgLayout.length; i++) { 
    90123         var elem = document.getElementById('msgval'+otgjsInfoMsgLayout[i][0]); 
    91          var msg = otgjsConfig[otgjsInfoMsgLayout[i][0]]; 
    92          var val = get_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", msg.var, 1); 
     124         var msg = otgjsMessage[otgjsInfoMsgLayout[i][0]]; 
     125         var msgVar = msg.var 
     126         if (typeof(msgVar) == 'object') { 
     127            msgVar = msgVar[otgjsInfoMsgLayout[i][4]] 
     128         } 
     129         var val = otgjsGetVariableState(deviceObj, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", msgVar); 
    93130         elem.innerHTML = (val == null ? "???" : val); 
    94131      } 
    95       setTimeout("otgjsDisplayInfo("+deviceID+")", 500); 
     132      // Update error count 
     133      var val = otgjsGetVariableState(deviceObj, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", "Errors"); 
     134      var val_a = val.split(','); 
     135      for (var i=0; i<val_a.length; i++) { 
     136         var elem = document.getElementById('errval'+i); 
     137         elem.innerHTML = val_a[i]; 
     138      } 
     139      setTimeout("otgjsDisplayInfo("+deviceID+")", 1000); 
    96140   } 
    97141}; 
    98142 
    99143function otgjsInfoConfig(deviceID, result) { 
    100    otgjsConfig = result; 
     144   otgjsMessage = result; 
    101145   // Add flag labels 
    102146   for (var i=0; i<otgjsInfoFlagLayout.length; i++) { 
    103147      var elem = document.getElementById('flag'+otgjsInfoFlagLayout[i][0]); 
    104       var msg = otgjsConfig[0].flags[otgjsInfoFlagLayout[i][0]]; 
     148      var msg = otgjsMessage[0].flags[otgjsInfoFlagLayout[i][0]]; 
    105149      elem.innerHTML = msg.txt; 
    106150   } 
     
    108152   for (var i=0; i<otgjsInfoFaultLayout.length; i++) { 
    109153      var elem = document.getElementById('fault'+otgjsInfoFaultLayout[i][0]); 
    110       var msg = otgjsConfig[5].flags[otgjsInfoFaultLayout[i][0]]; 
     154      var msg = otgjsMessage[5].flags[otgjsInfoFaultLayout[i][0]]; 
    111155      elem.innerHTML = msg.txt; 
    112156   } 
     
    114158   for (var i=0; i<otgjsInfoMsgLayout.length; i++) { 
    115159      var elem = document.getElementById('msg'+otgjsInfoMsgLayout[i][0]); 
    116       var msg = otgjsConfig[otgjsInfoMsgLayout[i][0]]; 
    117       elem.innerHTML = msg.txt; 
     160      var msg = otgjsMessage[otgjsInfoMsgLayout[i][0]]; 
     161      var txt = msg.txt; 
     162      var sub = otgjsInfoMsgLayout[i][4]; 
     163      if (sub != null) { 
     164         var n = txt.search("&"); 
     165         if (sub == 'lb') { txt = txt.substr(n+1); } else { txt = txt.substr(0, n-1); } 
     166      } 
     167      elem.innerHTML = txt; 
     168   } 
     169   // Add error labels 
     170   for (var i=0; i<4; i++) { 
     171      var elem = document.getElementById('err'+i); 
     172      elem.innerHTML = "Error 0"+(i+1)+":"; 
    118173   } 
    119174   otgjsDisplayInfo(deviceID); 
     
    124179 
    125180function otgjsSettingsTab(deviceID) { 
     181   if (otgjsConfig == undefined) { 
     182      otgjsConfig = otgjsGetInfo(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", 'GetConfiguration', 0, false); 
     183   } 
    126184   var deviceObj = get_device_obj(deviceID); 
    127185   var devicePos = get_device_index(deviceID) 
    128    var html = ''; 
    129    html += '<table width="70%" border="0" cellspacing="3" cellpadding="0">'; 
    130    html += '<tr><td colspan="3"><div class="label"><b>General options</b></div></td></tr>'; 
     186   var html = '<style>span.customStyleSelectBox {border:0}</style>'; 
     187   html += '<table width="100%" border="0" cellspacing="3" cellpadding="0">'; 
     188   html += '<tr><td colspan="3"><div class="label"><b>Plugin options</b></div></td></tr>'; 
    131189    
    132190   if (deviceObj.commUse) { 
     
    141199      html += '</tr>'; 
    142200   } 
    143    var modes = [{'value':'Gateway','label':'Gateway'}, {'value':'Monitor','label':'Monitor'}]; 
    144    html += otgjsAddButtons(deviceID, 'Generate debug logging & files', 'PluginDebug'); 
    145    html += '<tr><td colspan="3"><div class="label"><b>Gateway options</b></div></td></tr>'; 
    146    html += otgjsAddPulldown(deviceID, 'Gateway mode', 'GatewayMode', modes); 
     201   // Make list of temerature sensors 
     202   var sensors = [{'value':'','label':'None'}]; 
     203   var devicesCount = jsonp.ud.devices.length; 
     204   for (var i=0; i<devicesCount; i++){ 
     205      if (jsonp.ud.devices[i].category_num == 17) { 
     206         sensors.push({ 'value':jsonp.ud.devices[i].id,'label':jsonp.ud.devices[i].name }); 
     207      } 
     208   } 
     209   var debug = [{'value':'0','label':'Off'},{'value':'1','label':'On'}]; 
     210   html += otgjsAddPulldown(deviceID, 'Generate debug logging & files', 'PluginDebug', debug); 
     211   html += otgjsAddPulldown(deviceID, 'Outside temperature sensor', 'OutsideSensorDevice', sensors); 
     212   html += '<tr><td colspan="3"><div class="label"><b>Gateway configuration</b></div></td></tr>'; 
     213   for (var elem in otgjsConfig) { 
     214      if (otgjsConfig[elem].cmd != undefined) { 
     215         var list = []; 
     216         for (var prop in otgjsConfig[elem].tab) { 
     217            list.push({ 'value':prop,'label':otgjsConfig[elem].tab[prop].txt }); 
     218         } 
     219         if (elem != "LED") { 
     220            html += otgjsAddPulldown(deviceID, otgjsConfig[elem].txt, otgjsConfig[elem].var, list); 
     221         } else { 
     222            for (var i=0; i<4; i++){ 
     223               html += otgjsAddPulldown(deviceID, 'LED '+String.fromCharCode(65+i)+' function', 'LED'+i, list); 
     224            } 
     225         } 
     226      } 
     227   } 
    147228   html += '</table>'; 
    148229 
    149230   set_panel_html(html); 
    150    otgjsSettingsButtons(deviceID); 
    151 } 
    152  
    153 function otgjsSettingsButtons(deviceID) { 
    154    var dataLen = otgjsButtons.length; 
    155    for (var i = 0; i < dataLen; i++) { 
    156       var state = get_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", otgjsButtons[i], 0) 
    157       if (state == "1") { 
    158          document.getElementById(otgjsButtons[i] + 'On').className = "button selected"; 
    159          document.getElementById(otgjsButtons[i] + 'Off').className = "button"; 
    160       } else { 
    161          document.getElementById(otgjsButtons[i] + 'Off').className = "button selected"; 
    162          document.getElementById(otgjsButtons[i] + 'On').className = "button"; 
    163       } 
    164    } 
    165231} 
    166232 
    167233function otgjsUpdate(deviceID, variable, value) { 
    168    set_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", variable, value, 0); 
    169    otgjsSettingsButtons(deviceID); 
     234   if (variable.search("LED") >= 0) { 
     235      var idx = Number(variable.charAt(3)); 
     236      variable = "LEDFunctions"; 
     237      var state = get_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", variable, 0); 
     238      value = state.substr(0, idx) + value + state.substr(idx+1); 
     239      set_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", variable, value, 0); 
     240   } else { 
     241      set_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", variable, value, 0); 
     242      otgjsSettingsButtons(deviceID); 
     243   } 
    170244} 
    171245 
    172246function otgjsAddPulldown(deviceID, label, variable, values, extra) { 
    173247   extra = (extra == null) ? '' : extra; 
    174    var selected = get_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", variable, 0); 
     248   var selected; 
     249   if (variable.search("LED") >= 0) { 
     250      var idx = Number(variable.charAt(3)); 
     251      var state = get_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", "LEDFunctions", 0); 
     252      selected = (state == null ? '' : state.substr(idx, 1)); 
     253   } else { 
     254      selected = get_device_state(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", variable, 0); 
     255   } 
    175256   var pulldown = pulldown_from_array(values, variable + 'Select', selected, 'onChange="otgjsUpdate(' + deviceID + ', \'' + variable + '\', this.value)"'); 
    176    var html = '<tr><td><div class="label">' + label + '</div></td><td colspan="2">' + pulldown + '</td><td>' + extra + '</td></tr>'; 
     257   var html = '<tr><td><div class="label" id="+variable+">' + label + '</div></td><td colspan="2">' + pulldown + '</td><td>' + extra + '</td></tr>'; 
    177258 
    178259   return html; 
     
    231312} 
    232313 
    233 function otgjsGetInfo(device, sid, what, func) { 
     314function otgjsGetInfo(device, sid, what, func, async) { 
     315   var result = ''; 
    234316   new Ajax.Request("../port_3480/data_request", {  
    235317     method: "get",  
    236      asynchronous: true, 
     318     asynchronous: (async == undefined ? true : async), 
    237319     parameters: {  
    238320         id: 'lr_' + what + device, 
     
    246328     },  
    247329     onComplete: function (response) {  
    248          var result = response.responseText.evalJSON(); 
    249          func(device, result) 
     330         result = response.responseText.evalJSON(); 
     331         if (async != false) { 
     332            func(device, result); 
     333         } 
    250334     } 
    251335   }); 
    252 } 
     336   return result; 
     337} 
  • /trunk/I_OpenThermGateway.xml

    r1 r3  
    2626      otgMessage = pluginLib.otgMessage 
    2727      otgCallbackHandler = pluginLib.otgCallbackHandler 
     28      otgSetOutsideTempCallback = pluginLib.otgSetOutsideTempCallback 
    2829 
    2930        luup.log("OTG: library L_OpenThermGateway loaded") 
     
    6061      </run> 
    6162   </action> 
    62    </actionList> 
     63 
     64   <action> 
     65      <serviceId>urn:otgw-tclcode-com:serviceId:OpenThermGateway1</serviceId> 
     66      <name>SetOutsideTemperature</name> 
     67      <run> 
     68         if (pluginLib ~= nil) then pluginLib.otgSetOutsideTemperature(lul_settings.NewTemperature) end 
     69      </run> 
     70   </action> 
     71 
     72   <action> 
     73      <serviceId>urn:otgw-tclcode-com:serviceId:OpenThermGateway1</serviceId> 
     74      <name>SendCommand</name> 
     75      <run> 
     76         if (pluginLib ~= nil) then pluginLib.otgSendCommand(lul_settings.Command) end 
     77      </run> 
     78   </action> 
     79  </actionList> 
    6380</implementation> 
  • /trunk/L_OpenThermGateway.lua

    r1 r3  
    44local socket = require("socket") -- needed for accurate timing 
    55 
    6 ------------------------------------------------- 
    7 -- Control the OpenTherm Gateway via Mios Vera -- 
    8 ------------------------------------------------- 
     6------------------------------------------------------------- 
     7-- Monitor and control the OpenTherm Gateway via Mios Vera -- 
     8------------------------------------------------------------- 
    99  
    10 local OTG_PLUGIN_VERSION = "0.1" 
     10local OTG_PLUGIN_VERSION = "0.3" 
     11 
     12--- QUEUE STRCUTURE --- 
     13local Queue = {} 
     14function Queue.new() 
     15   return {first = 0, last = -1} 
     16end 
     17 
     18function Queue.push(list, value) 
     19   local last = list.last + 1 
     20   list.last = last 
     21   list[last] = value 
     22end 
     23     
     24function Queue.pop(list) 
     25   local first = list.first 
     26   if first > list.last then return nil end 
     27   local value = list[first] 
     28   list[first] = nil -- to allow garbage collection 
     29   list.first = first + 1 
     30   return value 
     31end 
     32 
     33function Queue.len(list) 
     34   return list.last - list.first + 1 
     35end 
    1136 
    1237--- SERVICES --- 
     
    2146--- DEVICES --- 
    2247local otgDevice 
     48local otgOutsideSensor 
    2349 
    2450--- DYNAMIC VALUES --- 
    25 local otgErrorCnt_t = { 0, 0, 0, 0 } 
     51local otgErrorCnt_t = {} 
    2652local otgLastStatus = 0 
     53local otgGatewayMode = false 
     54local otgExpectingResponse = false 
     55local otgResponseQueue = Queue.new() 
    2756 
    2857--- DEBUGGING --- 
     
    3463local otgPluginInit_t = { -- false: update; true: create only 
    3564   { "PluginVersion", OTG_PLUGIN_VERSION, false }, 
    36    { "PluginDebug", "1", true }, 
     65   { "PluginDebug", "0", true }, 
    3766   { "LogPath", otgLogPath, true }, 
    38    { "GatewayMode", "Monitor", true } 
    39 } 
    40  
     67   { "GatewayMode", "", true }, 
     68   { "CommandResponse", "", false }, 
     69   { "Errors", "0,0,0,0", true } 
     70} 
     71 
     72-- OpenTherm Gateway operating modes 
     73local otgGatewayMode_t = { 
     74   [0] = { txt = "Monitor" }, 
     75   [1] = { txt = "Gateway" } 
     76} 
     77 
     78-- OpenTherm Gateway LED functions 
     79local otgLedFunction_t = { 
     80   R = { txt = "Receiving an OpenTherm message from the thermostat or boiler" }, 
     81   X = { txt = "Transmitting an OpenTherm message to the thermostat or boiler" }, 
     82   T = { txt = "Transmitting or receiving a message on the master interface" }, 
     83   B = { txt = "Transmitting or receiving a message on the slave interface" }, 
     84   O = { txt = "Remote setpoint override is active" }, 
     85   F = { txt = "Flame is on", var = "FlameStatus" }, 
     86   H = { txt = "Central heating is on", var = "CHMode" }, 
     87   W = { txt = "Hot water is on", var = "DHWMode" }, 
     88   C = { txt = "Comfort mode (Domestic Hot Water Enable) is on", var = "DHWEnabled" }, 
     89   E = { txt = "Transmission error has been detected", var = "Errors" }, 
     90   M = { txt = "Boiler requires maintenance", var = "DiagnosticEvent" } 
     91} 
     92 
     93-- OpenTherm Gateway signal transition checking 
     94local otgIgnoreTrans_t = { 
     95   [0] = { txt = "Check" }, 
     96   [1] = { txt = "Ignore" } 
     97} 
     98 
     99-- OpenTherm Gateway reference voltage 
     100local otgRefVoltage_t = { 
     101   [0] = { txt = "0.625V" }, 
     102   [1] = { txt = "0.833V" }, 
     103   [2] = { txt = "1.042V" }, 
     104   [3] = { txt = "1.250V" }, 
     105   [4] = { txt = "1.458V" }, 
     106   [5] = { txt = "1.667V" }, 
     107   [6] = { txt = "1.875V" }, 
     108   [7] = { txt = "2.083V" }, 
     109   [8] = { txt = "2.292V" }, 
     110   [9] = { txt = "2.500V" }, 
     111} 
     112 
     113-- OpenTherm Gateway domestic hot water setting 
     114local otgDHWsetting_t = { 
     115   [0] = { txt = "Off" }, 
     116   [1] = { txt = "On (comfort mode)" }, 
     117    A  = { txt = "Thermostat controlled" } 
     118} 
     119 
     120-- OpenTherm Gateway message types 
    41121local otgMsgInitiator_t = { 
    42122   A = "Answer", B = "Boiler", R = "Request", T = "Thermostat" 
    43123} 
    44124 
     125-- OpenTherm message type 
    45126local otgMsgType_t = { 
    46127   [0] = "Read-Data", [1] = "Write-Data", [2] = "Invalid-Data", [3] = "-reserved-",  
     
    48129} 
    49130 
    50 -- OpenTherm message flags 
    51  
    52 local otgStatusFlag_t = { -- ID 0: Master status (HB) & Slave status (LB) 
    53    [0x0100] = { txt = "Central Heating enable", var = "CHEnabled" }, 
    54    [0x0200] = { txt = "Domestic Hot Water enable", var = "DHWEnabled" }, 
     131-- OpenTherm status flags [ID 0: Master status (HB) & Slave status (LB)] 
     132local otgStatusFlag_t = { 
     133   [0x0100] = { txt = "Central heating enable", var = "CHEnabled" }, 
     134   [0x0200] = { txt = "Domestic hot water enable", var = "DHWEnabled" }, 
    55135   [0x0400] = { txt = "Cooling enable", var = "CoolEnabled" }, 
    56    [0x0800] = { txt = "OTC active", var = "OTCActive" }, 
    57    [0x1000] = { txt = "Central Heating 2 enable", var = "CH2Enabled" }, 
     136   [0x0800] = { txt = "Outside temp. comp. active", var = "OTCActive" }, 
     137   [0x1000] = { txt = "Central heating 2 enable", var = "CH2Enabled" }, 
    58138   [0x0001] = { txt = "Fault indication", var = "Fault" }, -- no fault/fault 
    59    [0x0002] = { txt = "Central Heating mode", var = "CHMode" }, -- not active/active 
    60    [0x0004] = { txt = "Domestic Hot Water mode", var = "DHWMode" }, -- not active/active 
     139   [0x0002] = { txt = "Central heating mode", var = "CHMode" }, -- not active/active 
     140   [0x0004] = { txt = "Domestic hot water mode", var = "DHWMode" }, -- not active/active 
    61141   [0x0008] = { txt = "Flame status", var = "FlameStatus" }, -- flame off/on 
    62142   [0x0010] = { txt = "Cooling status", var = "CoolingStatus" }, -- not active/active 
    63    [0x0020] = { txt = "Central Heating 2 mode", var = "CH2Mode" }, -- not active/active 
     143   [0x0020] = { txt = "Central heating 2 mode", var = "CH2Mode" }, -- not active/active 
    64144   [0x0040] = { txt = "Diagnostic indication", var = "DiagnosticEvent" } -- no diagnostics/diagnostics event 
    65145} 
    66146 
    67 local otgFaultFlag_t = { -- ID 5: Application-specific fault flags (HB) 
     147-- OpenTherm configuration flags [ID 3: master/slave config flags (HB)] 
     148local otgConfigFlag_t = { 
     149   [0x0100] = { txt = "Domestic hot water present", var = "ConfigDHWpresent" }, 
     150   [0x0200] = { txt = "Control type (modulating on/off)", var = "ConfigControlType" }, 
     151   [0x0400] = { txt = "Cooling supported", var = "ConfigCooling" }, 
     152   [0x0800] = { txt = "Domestic hot water storage tank", var = "ConfigDHW" }, 
     153   [0x1000] = { txt = "Master low-off & pump control allowed", var = "ConfigMasterPump" }, 
     154   [0x2000] = { txt = "Central heating 2 present", var = "ConfigCH2" } 
     155} 
     156 
     157-- OpenTherm fault flags [ID 5: Application-specific fault flags (HB)] 
     158local otgFaultFlag_t = { 
    68159   [0x0100] = { txt = "Service request", var = "FaultServiceRequest" }, 
    69160   [0x0200] = { txt = "Lockout-reset", var = "FaultLockoutReset" }, 
     
    75166 
    76167-- OpenTherm messages 
    77  
    78168local otgMessage_t = { 
    79    [0] = { txt = "Status", val = "flag8", var = nil, flags = otgStatusFlag_t }, 
    80    [1] = { txt = "Control setpoint", val = "f8.8", var = "ControlSetpoint" }, 
    81    [2] = { txt = "Master configuration" }, 
    82    [3] = { txt = "Slave configuration" }, 
    83    [4] = { txt = "Remote command" }, 
    84    [5] = { txt = "Application-specific flags", val = "flag8", flags = otgFaultFlag_t }, 
    85    [6] = { txt = "Remote parameter flags", val = "flag8", var = nil }, 
    86    [8] = { txt = "Control setpoint 2" }, 
    87    [9] = { txt = "Remote override room setpoint" }, 
    88    [14] = { txt = "Maximum relative modulation level", val = "f8.8", var = "MaxRelModLevel" }, 
    89    [15] = { txt = "Boiler capacity and modulation limits", val = "u8", var = nil }, 
    90    [16] = { txt = "Room Setpoint", val = "f8.8", sid = OTG_TEMP_SETP_SID, var = "CurrentSetpoint" }, 
    91    [17] = { txt = "Relative modulation level", val = "f8.8", var = "RelModLevel" }, 
    92    [18] = { txt = "CH water pressure", val = "f8.8", var = nil }, 
    93    [19] = { txt = "DHW flow rate", val = "f8.8" }, 
    94    [20] = { txt = "Day of week & time of day" }, 
    95    [21] = { txt = "Date" }, 
    96    [22] = { txt = "Year", val = "u16" }, 
    97    [23] = { txt = "Room setpoint CH2", val = "f8.8" }, 
    98    [24] = { txt = "Room temperature", val = "f8.8", sid = OTG_TEMP_SENS_SID, var = "CurrentTemperature" }, 
    99    [25] = { txt = "Boiler water temperature", val = "f8.8", var = "BoilerWaterTemp" }, 
    100    [26] = { txt = "DHW temperature", val = "f8.8", var = "DHWTemp" }, 
    101    [27] = { txt = "Outside temperature", val = "f8.8", var = "OutsideTemp" }, 
    102    [28] = { txt = "Return water temperature", val = "f8.8", var = "ReturnWaterTemp" }, 
    103    [29] = { txt = "Solar storage temperature", val = "f8.8" }, 
    104    [30] = { txt = "Solar collector temperature", val = "s16" }, 
    105    [31] = { txt = "Flow temperature CH2", val = "f8.8" }, 
    106    [32] = { txt = "DHW2 temperature", val = "f8.8" }, 
    107    [33] = { txt = "Exhaust temperature", val = "s16" }, 
    108    [48] = { txt = "DHW setpoint boundaries", val = "u8", var = nil }, 
    109    [49] = { txt = "Max CH setpoint boundaries", val = "u8", var = nil }, 
    110    [56] = { txt = "DHW setpoint", val = "f8.8", var = "DHWSetpoint" }, 
    111    [57] = { txt = "Max CH water setpoint", val = "f8.8", var = nil }, 
    112    [100] = { txt = "Remote override function" }, 
    113    [115] = { txt = "OEM diagnostic code" }, 
    114    [116] = { txt = "Burner starts", val = "u16", var = nil }, 
    115    [117] = { txt = "CH pump starts", val = "u16", var = nil }, 
    116    [118] = { txt = "DHW pump/valve starts", val = "u16", var = nil }, 
    117    [119] = { txt = "DHW burner starts", val = "u16", var = nil }, 
    118    [120] = { txt = "Burner operation hours", val = "u16", var = nil }, 
    119    [121] = { txt = "CH pump operation hours", val = "u16", var = nil }, 
    120    [122] = { txt = "DHW pump/valve operation hours", val = "u16", var = nil }, 
    121    [123] = { txt = "DHW burner operation hours", val = "u16", var = nil }, 
    122    [124] = { txt = "Opentherm version Master", val = "f8.8" }, 
    123    [125] = { txt = "Opentherm version Slave", val = "f8.8" }, 
    124    [126] = { txt = "Master product version", val = "u8" }, 
    125    [127] = { txt = "Slave product version", val = "u8" }, 
     169   [ 0] = { dir = "R-", txt = "Status", val = "flag8", flags = otgStatusFlag_t }, 
     170   [ 1] = { dir = "-W", txt = "Control setpoint (&deg;C)", val = "f8.8", var = "ControlSetpoint" }, 
     171   [ 2] = { dir = "-W", txt = "Master configuration", val = { hb = "flag8", lb = "u8" } }, 
     172   [ 3] = { dir = "R-", txt = "Slave configuration", val = { hb = "flag8", lb = "u8" }, flags = otgConfigFlag_t }, 
     173   [ 4] = { dir = "-W", txt = "Remote command", val = "u8" }, 
     174   [ 5] = { dir = "R-", txt = "Fault flags & OEM fault code", val = { hb = "flag8", lb = "u8" }, var = { lb = "FaultCode" }, flags = otgFaultFlag_t }, 
     175   [ 6] = { dir = "R-", txt = "Remote parameter flags", val = "flag8" }, 
     176   [ 7] = { dir = "-W", txt = "Cooling control signal (%)", var = "f8.8" }, 
     177   [ 8] = { dir = "-W", txt = "Control setpoint 2 (&deg;C)", var = "f8.8" }, 
     178   [ 9] = { dir = "R-", txt = "Remote override room setpoint (&deg;C)", val = "f8.8", var ="RemoteOverrideRoomSetpoint" }, 
     179   [10] = { dir = "R-", txt = "Number of transparent slave parameters (TSP) supported by slave", val = "u8" }, 
     180   [11] = { dir = "RW", txt = "Index number/value of referred-to transparent slave parameter (TSP)", val = "u8" }, 
     181   [12] = { dir = "R-", txt = "Size of fault history buffer (FHB) supported by slave", val = "u8" }, 
     182   [13] = { dir = "R-", txt = "Index number/value of referred-to fault history buffer (FHB) entry", val = "u8" }, 
     183   [14] = { dir = "-W", txt = "Max. relative modulation level (%)", val = "f8.8", var = "MaxRelativeModulationLevel" }, 
     184   [15] = { dir = "R-", txt = "Max. boiler capacity (kW) and modulation level setting (%)", val = "u8" }, 
     185   [16] = { dir = "-W", txt = "Room setpoint (&deg;C)", val = "f8.8", sid = OTG_TEMP_SETP_SID, var = "CurrentSetpoint" }, 
     186   [17] = { dir = "R-", txt = "Relative modulation level (%)", val = "f8.8", var = "RelativeModulationLevel" }, 
     187   [18] = { dir = "R-", txt = "Central heating water pressure (bar)", val = "f8.8", var = "CHWaterPressure" }, 
     188   [19] = { dir = "R-", txt = "Domestic hot water flow rate (litres/minute)", val = "f8.8" }, 
     189   [20] = { dir = "RW", txt = "Day of week & time of day" }, 
     190   [21] = { dir = "RW", txt = "Date", val = "u8" }, 
     191   [22] = { dir = "RW", txt = "Year", val = "u16" }, 
     192   [23] = { dir = "-W", txt = "Room setpoint CH2 (&deg;C)", val = "f8.8" }, 
     193   [24] = { dir = "-W", txt = "Room temperature (&deg;C)", val = "f8.8", sid = OTG_TEMP_SENS_SID, var = "CurrentTemperature" }, 
     194   [25] = { dir = "R-", txt = "Boiler water temperature (&deg;C)", val = "f8.8", var = "BoilerWaterTemperature" }, 
     195   [26] = { dir = "R-", txt = "Domestic hot water temperature (&deg;C)", val = "f8.8", var = "DHWTemperature" }, 
     196   [27] = { dir = "R-", txt = "Outside temperature (&deg;C)", val = "f8.8", var = "OutsideTemperature" }, 
     197   [28] = { dir = "R-", txt = "Return water temperature (&deg;C)", val = "f8.8", var = "ReturnWaterTemperature" }, 
     198   [29] = { dir = "R-", txt = "Solar storage temperature (&deg;C)", val = "f8.8" }, 
     199   [30] = { dir = "R-", txt = "Solar collector temperature (&deg;C)", val = "s16" }, 
     200   [31] = { dir = "R-", txt = "Flow temperature central heating 2 (&deg;C)", val = "f8.8" }, 
     201   [32] = { dir = "R-", txt = "Domestic hot water 2 temperature (&deg;C)", val = "f8.8", var = "DHW2Temperature" }, 
     202   [33] = { dir = "R-", txt = "Boiler exhaust temperature (&deg;C)", val = "s16" }, 
     203   [48] = { dir = "R-", txt = "Domestic hot water setpoint boundaries (&deg;C)", val = "s8" }, 
     204   [49] = { dir = "R-", txt = "Max. central heating setpoint boundaries (&deg;C)", val = "s8" }, 
     205   [50] = { dir = "R-", txt = "OTC heat curve ratio upper & lower bounds", val = "s8" }, 
     206   [56] = { dir = "RW", txt = "Domestic hot water setpoint (&deg;C)", val = "f8.8", var = "DHWSetpoint" }, 
     207   [57] = { dir = "RW", txt = "Max. central heating water setpoint (&deg;C)", val = "f8.8", var = "MaxCHWaterSetpoint" }, 
     208   [58] = { dir = "RW", txt = "OTC heat curve ratio (&deg;C)", val = "f8.8" }, 
     209   [100] = { dir = "R-", txt = "Remote override function", val = { hb = "flag8", lb = "u8" }, var = { hb = "RemoteOverrideFunction" } }, 
     210   [115] = { dir = "R-", txt = "OEM diagnostic code", val = "u16" }, 
     211   [116] = { dir = "RW", txt = "Number of starts burner", val = "u16" }, 
     212   [117] = { dir = "RW", txt = "Number of starts central heating pump", val = "u16" }, 
     213   [118] = { dir = "RW", txt = "Number of starts domestic hot water pump/valve", val = "u16" }, 
     214   [119] = { dir = "RW", txt = "Number of starts burner during domestic hot water mode", val = "u16" }, 
     215   [120] = { dir = "RW", txt = "Number of hours that burner is in operation (i.e. flame on)", val = "u16" }, 
     216   [121] = { dir = "RW", txt = "Number of hours that central heating pump has been running", val = "u16" }, 
     217   [122] = { dir = "RW", txt = "Number of hours that domestic hot water pump has been running/valve has been opened", val = "u16" }, 
     218   [123] = { dir = "RW", txt = "Number of hours that domestic hot water burner is in operation during DHW mode", val = "u16" }, 
     219   [124] = { dir = "-W", txt = "Opentherm version Master", val = "f8.8" }, 
     220   [125] = { dir = "R-", txt = "Opentherm version Slave", val = "f8.8" }, 
     221   [126] = { dir = "-W", txt = "Master product version and type", val = "u8" }, 
     222   [127] = { dir = "R-", txt = "Slave product version and type", val = "u8" } 
     223} 
     224 
     225local otgConfig_t = { 
     226   VER = { txt = "Gateway firmware version", var = "FirmwareVersion", rep = "A", ret = "OpenTherm Gateway (.*)" }, 
     227   GW  = { txt = "Operating mode", tab = otgGatewayMode_t, var = "GatewayMode", cmd = "GW", rep = "G", ret = "[0|1]"}, 
     228   LED = { txt = "LED <> function", tab = otgLedFunction_t, var = "LEDFunctions", cmd = "LA", rep = "L", ret = "[R|X|T|B|O|F|H|W|C|E|M]+" }, 
     229   ITR = { txt = "Non-significant transitions", tab = otgIgnoreTrans_t, var = "IgnoreTransitions", cmd = "IT", rep = "T", ret = "[0|1]" }, 
     230   REF  = { txt = "Reference voltage", tab = otgRefVoltage_t, var = "ReferenceVoltage", cmd = "VR", rep = "V", ret = "%d" }, 
     231   HOT  = { txt = "Domestic hot water enable ", tab = otgDHWsetting_t, var = "DHWSetting", cmd = "HW", rep = "W", ret = "[0|1|A]" } 
    126232} 
    127233 
     
    132238-- Update a system variable only if the value will change 
    133239function updateIfNeeded(sid, var, newVal, id, createOnly) 
    134    local curVal = luup.variable_get(sid, var, id) 
    135    local valUpdate = (curVal == nil) or ((createOnly ~= true) and (curVal ~= tostring(newVal)) or false) 
    136    if (valUpdate == true) then 
    137       luup.variable_set(sid, var, newVal, id) 
    138       return true 
     240   if (sid ~= nil and var ~= nil and newVal ~= nil and id ~= nil) then 
     241      local curVal = luup.variable_get(sid, var, id) 
     242      local valUpdate = (curVal == nil) or ((createOnly ~= true) and (curVal ~= tostring(newVal)) or false) 
     243      if (valUpdate == true) then 
     244         luup.variable_set(sid, var, newVal, id) 
     245         return true 
     246      end 
    139247   end 
    140248   return false 
     
    213321end 
    214322 
     323-- otgDecodeMessage 
     324function otgDecodeMessage(val1, msgVal, val2) 
     325   local val = "" 
     326   if (msgVal == "u16") then -- unsigned 16 
     327      val = val1 * 256 + val2 
     328   elseif (msgVal == "s16") then -- signed 16 
     329      val = -32767 + val1 * 256 + val2 
     330   elseif (msgVal == "f8.8") then -- floating point 
     331      val1 = val1 + 1/256 * val2 
     332      val = string.format("%.2f", val1) -- high accuracy 
     333   else -- byte only types 
     334      if (msgVal == "flag8") then -- flag 8 
     335         local i 
     336         for i = 7, 0, -1 do 
     337            val = val .. ((bitw.band(val1, 2^i) == 0) and "0" or "1") 
     338         end 
     339      elseif (msgVal == "u8") then -- unsigned 8 
     340         val = string.format("%d", val1) 
     341      elseif (msgVal == "s8") then -- signed 8 
     342         val = string.format("%d", -127 + val1) 
     343      end 
     344      if (val2 ~= nil) then 
     345         val = val .. " " .. otgDecodeMessage(val2, msgVal) 
     346      end 
     347   end 
     348   return val 
     349end 
     350 
    215351-- otgWriteCommand: write a command to the OTG 
    216 function otgWriteCommand(cmd) 
     352function otgWriteCommand(cmd, response) 
    217353   local success = luup.io.write(cmd, otgDevice) 
     354   debug("Sent command " .. cmd) 
    218355   if (success == false) then 
    219356      otgMessage("Cannot send message to the OpenTherm Gateway", 2) 
    220357      return false 
     358   end 
     359   if (response ~= nil) and (response == true) then 
     360      updateIfNeeded(OTG_GATEWAY_SID, "CommandResponse", "", otgDevice) 
     361      otgExpectingResponse = true 
     362   elseif (response == nil) then 
     363      Queue.push(otgResponseQueue, "OK") 
     364   elseif (type(response) == "string") then 
     365      Queue.push(otgResponseQueue, response) 
    221366   end 
    222367end 
     
    265410   end 
    266411    
    267    -- Request firmware version 
    268    local success = otgWriteCommand("PR=A") 
    269    if (success == false) then 
    270       return false 
     412   -- Update commands for firmware 4 (note: only happens on 2nd run) 
     413   local version = luup.variable_get(OTG_GATEWAY_SID, "FirmwareVersion", otgDevice) 
     414   if (version ~= nil) then 
     415      local major = tonumber(string.match(version, "(%d+)\.")) 
     416      if (major ~= nil and major > 3) then 
     417         otgConfig_t.GW.rep = "M" 
     418      end 
    271419   end 
    272420 
    273421   -- Register luup web handlers 
     422   luup.register_handler("otgCallbackHandler", "GetMessages" .. otgDevice) 
    274423   luup.register_handler("otgCallbackHandler", "GetConfiguration" .. otgDevice) 
    275424   luup.register_handler("otgCallbackHandler", "GetMessageFile" .. otgDevice) 
     425    
     426   -- Optional: Register outside sensor device 
     427   otgOutsideSensor = luup.variable_get(OTG_GATEWAY_SID, "OutsideSensorDevice", otgDevice) 
     428   if (otgOutsideSensor ~= nil and otgOutsideSensor ~= "") then 
     429      otgOutsideSensor = tonumber(otgOutsideSensor) 
     430      debug("Registering outside temperature sensor " .. otgOutsideSensor) 
     431      luup.variable_watch("otgSetOutsideTempCallback", OTG_TEMP_SENS_SID, "CurrentTemperature", otgOutsideSensor) 
     432   end 
     433    
     434   -- Get error count locally 
     435   local errors = luup.variable_get(OTG_GATEWAY_SID, "Errors", otgDevice) 
     436   string.gsub(errors, "([^,]+)", function(c) otgErrorCnt_t[#otgErrorCnt_t + 1] = tonumber(c) end) 
     437 
     438   -- Send report commands to Gateway to receive settings 
     439   for key, elem in pairs(otgConfig_t) do 
     440      otgWriteCommand("PR=" .. elem.rep, key) -- get OTG value 
     441   end 
     442 
     443   -- Store gateway mode locally 
     444   otgGatewayMode = (luup.variable_get(OTG_GATEWAY_SID, otgConfig_t.GW.var, otgDevice) == "1") 
     445   otgMessage("Started in " .. otgConfig_t.GW.tab[(otgGatewayMode and 1 or 0)].txt .. " mode.", 2) 
    276446end 
    277447 
     
    289459      local msgVal = "flag8" 
    290460      local msgVar = "" 
     461      local msgFlags = nil 
    291462      if (otgMessage_t[msg] ~= nil) then 
    292463         msgTxt = otgMessage_t[msg].txt 
    293464         msgVal = otgMessage_t[msg].val or "flag8" 
    294465         msgVar = otgMessage_t[msg].var or "" 
     466         msgFlags = otgMessage_t[msg].flags 
     467         if (msgVar == "" and msg > 0) then 
     468            debug("*** No variable for message " .. msg .. " (" .. msgTxt .. ") ***") 
     469         end 
    295470      end 
    296471      local val1 = tonumber("0x" .. string.sub(data, 6, 7)) 
     
    298473      local val = 0 
    299474      -- Format value 
    300       if (msgVal == "flag8") then 
    301          val = "" 
    302          local i, item 
    303          for i = 7, 0, -1 do 
    304             val = val .. ((bitw.band(val1, 2^i) == 0) and "0" or "1") 
    305          end 
    306          val = val .. " " 
    307          for i = 7, 0, -1 do 
    308             val = val .. ((bitw.band(val2, 2^i) == 0) and "0" or "1") 
    309          end 
    310       elseif (msgVal == "u8") then 
    311          val = string.format("%02x %02x", val1, val2) 
    312       elseif (msgVal == "u16") then 
    313          val = val1 * 256 + val2 
    314       elseif (msgVal == "f8.8") then 
    315          val1 = val1 + 1/256 * val2 
    316          val = string.format("%.2f", val1) -- high accuracy 
    317          val2 = string.format("%.1f", val1) -- low accuracy for variables 
     475      if (type(msgVal) == "table") then 
     476         val = otgDecodeMessage(val1, msgVal.hb) .. "," .. otgDecodeMessage(val2, msgVal.lb) 
     477      else 
     478         val = otgDecodeMessage(val1, msgVal, val2) 
    318479      end 
    319480      local s = string.format("%10s: %-14s %s = ", sender, ctype, msgTxt) .. val 
     
    321482      debug(s) 
    322483      -- Optional: decode flags 
    323       local flags = otgMessage_t[msg].flags 
    324484      val1 = val1 * 256 + val2 
    325       if (flags ~= nil) then 
    326          for i, item in pairs(flags) do 
     485      if (msgFlags ~= nil) then 
     486         for i, item in pairs(msgFlags) do 
    327487            local flagVal = ((bitw.band(val1, i) == 0) and "0" or "1") 
    328488            debug(">> " .. item.txt .. ": " .. flagVal) 
     
    336496         local sid = otgMessage_t[msg].sid or OTG_GATEWAY_SID 
    337497         if (msgVal == "f8.8" and sid ~= OTG_GATEWAY_SID) then 
     498            val2 = string.format("%.1f", tonumber(val)) 
    338499            updateIfNeeded(sid, msgVar, val2, otgDevice) -- use lower accuracy for non-gateway variables 
    339500            sid = OTG_GATEWAY_SID -- set high accuray value in gateway variable as well 
    340501         end 
    341          updateIfNeeded(sid, msgVar, val, otgDevice) 
     502         if (type(msgVar) == "table") then 
     503            local hb, lb = string.match(val, "([^,]*),(.*)") 
     504            updateIfNeeded(sid, msgVar.hb, hb, otgDevice) 
     505            updateIfNeeded(sid, msgVar.lb, lb, otgDevice) 
     506         else 
     507            updateIfNeeded(sid, msgVar, val, otgDevice) 
     508         end 
    342509      end 
    343510      -- Optional: Update MCV specific vars 
     
    350517         local modeState = "Idle" 
    351518         local modeStatus = "Off" 
    352          if (chEnabled == true and chMode == true) then 
     519         if (chEnabled == "1" and chMode == "1") then 
    353520            modeState = "Heating" 
    354521            modeStatus = "HeatOn" 
    355          elseif (chEnabled == true and chMode == false) then 
     522         elseif (chEnabled == "1" and chMode == "0") then 
    356523            modeState = "PendingHeat" 
    357          elseif (coolEnabled == true and coolMode == true) then 
     524         elseif (coolEnabled == "1" and coolMode == "1") then 
    358525            modeState = "Cooling" 
    359526            modeStatus = "CoolOn" 
    360          elseif (coolEnabled == true and coolMode == false) then 
     527         elseif (coolEnabled == "1" and coolMode == "0") then 
    361528            modeState = "PendingCool" 
    362529         end 
     
    364531         updateIfNeeded(OTG_HVAC_USER_SID, "ModeStatus", modeStatus, otgDevice) 
    365532      end 
    366    elseif (string.find(data, "OpenTherm Gateway") ~= nil) then -- PR=A 
    367       local ver = string.match(data, "%a+ %a+ (.*)") 
    368       debug("Firmware version " .. ver) 
    369       updateIfNeeded(OTG_GATEWAY_SID, "FirmwareVersion", ver, otgDevice) 
     533   elseif (otgExpectingResponse == true) then 
     534      otgExpectingResponse = false 
     535      updateIfNeeded(OTG_GATEWAY_SID, "CommandResponse", data, otgDevice) 
     536   elseif (Queue.len(otgResponseQueue) > 0) then 
     537      local elem = Queue.pop(otgResponseQueue) 
     538      local elem_t = otgConfig_t[elem] 
     539      if (elem_t ~= nil) then -- a known message 
     540         local val = string.match(data, elem_t.ret) -- check expected response 
     541         if (val ~= nil) then -- valid response 
     542            local valOld = luup.variable_get(OTG_GATEWAY_SID, elem_t.var, otgDevice) 
     543            if (valOld ~= nil and valOld ~= "" and valOld ~= val and elem_t.cmd ~= nil) then 
     544               val = valOld -- current setting takes precedence 
     545               if (elem == "LED") then 
     546                  otgWriteCommand("LA=" .. string.sub(val, 1, 1)) 
     547                  otgWriteCommand("LB=" .. string.sub(val, 2, 2)) 
     548                  otgWriteCommand("LC=" .. string.sub(val, 3, 3)) 
     549                  otgWriteCommand("LD=" .. string.sub(val, 4, 4)) 
     550               else 
     551                  otgWriteCommand(elem_t.cmd .. "=" .. val) 
     552               end 
     553            end 
     554            if (elem == "GW") then 
     555               otgGatewayMode = (val == "1") 
     556            end 
     557            updateIfNeeded(OTG_GATEWAY_SID, elem_t.var, val, otgDevice) 
     558         else 
     559            debug("Error for cmd: " .. elem .. "; expected " .. elem_t.ret .. " but got " .. data) 
     560         end 
     561      elseif (elem ~= data) then 
     562         debug("Error: expected " .. elem .. " but got " .. data) 
     563      end 
    370564   elseif (string.find(data, "Error") ~= nil) then -- Error received 
    371       local errNr = string.match(data, "(%d*)") 
     565      local errNr = tonumber(string.match(data, "(%d+)")) 
    372566      otgErrorCnt_t[errNr] = otgErrorCnt_t[errNr] + 1 
     567      local errors = "" 
     568      for i = 1, 4 do 
     569         errors = errors .. "," .. otgErrorCnt_t[i] 
     570      end 
     571      luup.variable_set(OTG_GATEWAY_SID, "Errors", string.sub(errors, 2), otgDevice) 
    373572   else 
    374573      debug("Unknown message") 
     
    377576end 
    378577 
    379 -- Action functions 
     578--- ACTION FUNCTIONS --- 
    380579 
    381580-- otgSetCurrentSetpoint 
    382581function otgSetCurrentSetpoint(NewCurrentSetpoint) 
    383582   debug("otgSetCurrentSetpoint " .. (NewCurrentSetpoint or "")) 
    384    local mode = luup.variable_get(OTG_GATEWAY_SID, "GatewayMode", otgDevice) 
    385    if (mode == "Gateway") then 
     583   if (otgGatewayMode == true) then 
    386584      return otgWriteCommand("TT=" .. NewCurrentSetpoint) -- Temperature temporary 
    387585   else 
    388       otgMessage("SetModeTarget only possible in Gateway mode", 2) 
     586      otgMessage("SetCurrentSetpoint only possible in Gateway mode", 2) 
    389587   end 
    390588end 
     
    393591function otgSetModeTarget(NewModeTarget) 
    394592   debug("otgSetModeTarget " .. (NewModeTarget or "")) 
    395    local mode = luup.variable_get(OTG_GATEWAY_SID, "GatewayMode", otgDevice) 
    396    if (mode == "Gateway") then 
     593   if (otgGatewayMode == true) then 
    397594      if (NewModeTarget == "Off") then 
    398595         return otgWriteCommand("TT=0") -- Schedule 
     
    406603      otgMessage("SetModeTarget only possible in Gateway mode", 2) 
    407604   end 
     605end 
     606 
     607function otgSetOutsideTempCallback(lul_device, lul_service, lul_variable, lul_value_old, lul_value_new) 
     608   debug("otgSetOutsideTempCallback " .. (lul_device or "") .. ", " .. (lul_value_new or "")) 
     609   if (lul_device == otgOutsideSensor) then 
     610      otgSetOutsideTemperature(lul_value_new) 
     611   end 
     612end 
     613 
     614-- otgSetOutsideTemperature 
     615function otgSetOutsideTemperature(NewTemperature) 
     616   debug("otgSetOutsideTemperature " .. (NewTemperature or "")) 
     617   if (otgGatewayMode == true) then 
     618      return otgWriteCommand("OT=" .. NewTemperature) -- Outside temperature 
     619   else 
     620      otgMessage("SetOutsideTemperature only possible in Gateway mode", 2) 
     621   end 
     622end 
     623 
     624-- otgSendCommand 
     625function otgSendCommand(Command) 
     626   debug("otgSendCommand " .. (Command or "")) 
     627   return otgWriteCommand(Command, true) -- no checking on input 
    408628end 
    409629 
     
    481701   debug("otgCallbackHandler: request " .. lul_request) 
    482702   if (lul_outputformat ~= "xml") then 
    483       if (lul_request == "GetConfiguration" .. otgDevice) then 
     703      if (lul_request == "GetMessages" .. otgDevice) then 
    484704         return table2Json(otgMessage_t) 
     705      elseif (lul_request == "GetConfiguration" .. otgDevice) then 
     706         return table2Json(otgConfig_t) 
    485707      elseif (lul_request == "GetMessageFile" .. otgDevice) then 
    486708         return dumpFile(otgLogFilename) 
Note: See TracChangeset for help on using the changeset viewer.