- Location:
- /trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
/trunk/D_OpenThermGateway.json
r1 r3 35 35 "FanMode": { 36 36 "Style": "numeric", 37 "Service": "urn: upnp-org: serviceId:HVAC_FanOperatingMode1",37 "Service": "urn:upnp-org:serviceId:HVAC_FanOperatingMode1", 38 38 "Variable": "ModeStatus" 39 39 } … … 170 170 }, 171 171 "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 } 172 256 } 173 257 ] … … 363 447 } 364 448 ], 365 "DeviceType": "urn:schemas-upnp-org:device:H eater:1"449 "DeviceType": "urn:schemas-upnp-org:device:HVAC_ZoneThermostat:1" 366 450 } -
/trunk/S_OpenThermGateway.xml
r1 r3 3 3 <specVersion> 4 4 <major>1</major> 5 <minor> 0</minor>5 <minor>1</minor> 6 6 </specVersion> 7 7 <serviceStateTable> … … 17 17 </stateVariable> 18 18 </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> 21 39 </scpd> -
/trunk/D_OpenThermGateway.xml
r1 r3 7 7 <device> 8 8 <deviceType>urn:schemas-upnp-org:device:HVAC_ZoneThermostat:1</deviceType> 9 <Category_Num>5</Category_Num>10 <SubCategory_Num>2</SubCategory_Num>11 9 <staticJson>D_OpenThermGateway.json</staticJson> 12 10 <serviceList> … … 17 15 </service> 18 16 <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> 23 62 </service> 24 63 </serviceList> -
/trunk/J_OpenThermGateway.js
r1 r3 1 1 var browserIE = false; 2 2 var otgjsButtons = new Array(); 3 var otgjsMessage; 3 4 var otgjsConfig; 4 5 5 6 // Flag ID, y, x1, x2 6 7 var 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, 23 0, 385],16 [0x0010, 100, 230, 385],17 [0x0020, 1 20, 30, 190],18 [0x0040, 120, 23 0, 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 19 20 ] 20 21 21 22 // Fault ID, y, x1, x2 22 23 var otgjsInfoFaultLayout = [ 23 [0x0100, 20, 4 25, 570],24 [0x0200, 40, 4 25, 570],25 [0x0400, 60, 4 25, 570],26 [0x0800, 80, 4 25, 570],27 [0x1000, 100, 4 25, 570],28 [0x2000, 120, 4 25, 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] 29 30 ] 30 31 31 // Message ID, y, x1, x2 32 // Message ID, y, x1, x2, optional: index hb/lb 32 33 var 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 43 48 ]; 44 49 … … 47 52 48 53 function 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>'; 51 60 for (var i=0; i<otgjsInfoFlagLayout.length; i++) { 52 61 html += '<div class="label" id="flag'+otgjsInfoFlagLayout[i][0]+'" style="position: absolute; top: '+otgjsInfoFlagLayout[i][1]+'px; left: '+otgjsInfoFlagLayout[i][2]+'px;"></div>'; … … 59 68 html += '<input type="checkbox" id="faultcheck'+otgjsInfoFaultLayout[i][0]+'" disabled><span></span></div>'; 60 69 } 70 html += '<div class="hr" style="position: absolute; top: 145px; left: 28px; width: 570px;"></div>'; 61 71 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 } 66 80 otgjsDetectBrowser(); 67 81 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 89 function 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 69 100 } 70 101 … … 72 103 // Keep updating while we are on this tab 73 104 if (document.getElementById('msg'+otgjsInfoMsgLayout[0][0]) != null) { 105 // Get the state of the device 106 var deviceObj = get_lu_status_device_obj(deviceID); 74 107 // Update flag values 75 108 for (var i=0; i<otgjsInfoFlagLayout.length; i++) { 76 109 var elem = document.getElementById('flagcheck'+otgjsInfoFlagLayout[i][0]); 77 var msg = otgjs Config[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); 79 112 elem.checked = (val == "1"); 80 113 } … … 82 115 for (var i=0; i<otgjsInfoFaultLayout.length; i++) { 83 116 var elem = document.getElementById('faultcheck'+otgjsInfoFaultLayout[i][0]); 84 var msg = otgjs Config[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); 86 119 elem.checked = (val == "1"); 87 120 } … … 89 122 for (var i=0; i<otgjsInfoMsgLayout.length; i++) { 90 123 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); 93 130 elem.innerHTML = (val == null ? "???" : val); 94 131 } 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); 96 140 } 97 141 }; 98 142 99 143 function otgjsInfoConfig(deviceID, result) { 100 otgjs Config= result;144 otgjsMessage = result; 101 145 // Add flag labels 102 146 for (var i=0; i<otgjsInfoFlagLayout.length; i++) { 103 147 var elem = document.getElementById('flag'+otgjsInfoFlagLayout[i][0]); 104 var msg = otgjs Config[0].flags[otgjsInfoFlagLayout[i][0]];148 var msg = otgjsMessage[0].flags[otgjsInfoFlagLayout[i][0]]; 105 149 elem.innerHTML = msg.txt; 106 150 } … … 108 152 for (var i=0; i<otgjsInfoFaultLayout.length; i++) { 109 153 var elem = document.getElementById('fault'+otgjsInfoFaultLayout[i][0]); 110 var msg = otgjs Config[5].flags[otgjsInfoFaultLayout[i][0]];154 var msg = otgjsMessage[5].flags[otgjsInfoFaultLayout[i][0]]; 111 155 elem.innerHTML = msg.txt; 112 156 } … … 114 158 for (var i=0; i<otgjsInfoMsgLayout.length; i++) { 115 159 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)+":"; 118 173 } 119 174 otgjsDisplayInfo(deviceID); … … 124 179 125 180 function otgjsSettingsTab(deviceID) { 181 if (otgjsConfig == undefined) { 182 otgjsConfig = otgjsGetInfo(deviceID, "urn:otgw-tclcode-com:serviceId:OpenThermGateway1", 'GetConfiguration', 0, false); 183 } 126 184 var deviceObj = get_device_obj(deviceID); 127 185 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> Generaloptions</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>'; 131 189 132 190 if (deviceObj.commUse) { … … 141 199 html += '</tr>'; 142 200 } 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 } 147 228 html += '</table>'; 148 229 149 230 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 }165 231 } 166 232 167 233 function 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 } 170 244 } 171 245 172 246 function otgjsAddPulldown(deviceID, label, variable, values, extra) { 173 247 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 } 175 256 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>'; 177 258 178 259 return html; … … 231 312 } 232 313 233 function otgjsGetInfo(device, sid, what, func) { 314 function otgjsGetInfo(device, sid, what, func, async) { 315 var result = ''; 234 316 new Ajax.Request("../port_3480/data_request", { 235 317 method: "get", 236 asynchronous: true,318 asynchronous: (async == undefined ? true : async), 237 319 parameters: { 238 320 id: 'lr_' + what + device, … … 246 328 }, 247 329 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 } 250 334 } 251 335 }); 252 } 336 return result; 337 } -
/trunk/I_OpenThermGateway.xml
r1 r3 26 26 otgMessage = pluginLib.otgMessage 27 27 otgCallbackHandler = pluginLib.otgCallbackHandler 28 otgSetOutsideTempCallback = pluginLib.otgSetOutsideTempCallback 28 29 29 30 luup.log("OTG: library L_OpenThermGateway loaded") … … 60 61 </run> 61 62 </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> 63 80 </implementation> -
/trunk/L_OpenThermGateway.lua
r1 r3 4 4 local socket = require("socket") -- needed for accurate timing 5 5 6 ------------------------------------------------- 7 -- Control the OpenTherm Gateway via Mios Vera --8 ------------------------------------------------- 6 ------------------------------------------------------------- 7 -- Monitor and control the OpenTherm Gateway via Mios Vera -- 8 ------------------------------------------------------------- 9 9 10 local OTG_PLUGIN_VERSION = "0.1" 10 local OTG_PLUGIN_VERSION = "0.3" 11 12 --- QUEUE STRCUTURE --- 13 local Queue = {} 14 function Queue.new() 15 return {first = 0, last = -1} 16 end 17 18 function Queue.push(list, value) 19 local last = list.last + 1 20 list.last = last 21 list[last] = value 22 end 23 24 function 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 31 end 32 33 function Queue.len(list) 34 return list.last - list.first + 1 35 end 11 36 12 37 --- SERVICES --- … … 21 46 --- DEVICES --- 22 47 local otgDevice 48 local otgOutsideSensor 23 49 24 50 --- DYNAMIC VALUES --- 25 local otgErrorCnt_t = { 0, 0, 0, 0}51 local otgErrorCnt_t = {} 26 52 local otgLastStatus = 0 53 local otgGatewayMode = false 54 local otgExpectingResponse = false 55 local otgResponseQueue = Queue.new() 27 56 28 57 --- DEBUGGING --- … … 34 63 local otgPluginInit_t = { -- false: update; true: create only 35 64 { "PluginVersion", OTG_PLUGIN_VERSION, false }, 36 { "PluginDebug", " 1", true },65 { "PluginDebug", "0", true }, 37 66 { "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 73 local otgGatewayMode_t = { 74 [0] = { txt = "Monitor" }, 75 [1] = { txt = "Gateway" } 76 } 77 78 -- OpenTherm Gateway LED functions 79 local 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 94 local otgIgnoreTrans_t = { 95 [0] = { txt = "Check" }, 96 [1] = { txt = "Ignore" } 97 } 98 99 -- OpenTherm Gateway reference voltage 100 local 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 114 local otgDHWsetting_t = { 115 [0] = { txt = "Off" }, 116 [1] = { txt = "On (comfort mode)" }, 117 A = { txt = "Thermostat controlled" } 118 } 119 120 -- OpenTherm Gateway message types 41 121 local otgMsgInitiator_t = { 42 122 A = "Answer", B = "Boiler", R = "Request", T = "Thermostat" 43 123 } 44 124 125 -- OpenTherm message type 45 126 local otgMsgType_t = { 46 127 [0] = "Read-Data", [1] = "Write-Data", [2] = "Invalid-Data", [3] = "-reserved-", … … 48 129 } 49 130 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)] 132 local otgStatusFlag_t = { 133 [0x0100] = { txt = "Central heating enable", var = "CHEnabled" }, 134 [0x0200] = { txt = "Domestic hot water enable", var = "DHWEnabled" }, 55 135 [0x0400] = { txt = "Cooling enable", var = "CoolEnabled" }, 56 [0x0800] = { txt = "O TCactive", 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" }, 58 138 [0x0001] = { txt = "Fault indication", var = "Fault" }, -- no fault/fault 59 [0x0002] = { txt = "Central Heating mode", var = "CHMode" }, -- not active/active60 [0x0004] = { txt = "Domestic Hot Water mode", var = "DHWMode" }, -- not active/active139 [0x0002] = { txt = "Central heating mode", var = "CHMode" }, -- not active/active 140 [0x0004] = { txt = "Domestic hot water mode", var = "DHWMode" }, -- not active/active 61 141 [0x0008] = { txt = "Flame status", var = "FlameStatus" }, -- flame off/on 62 142 [0x0010] = { txt = "Cooling status", var = "CoolingStatus" }, -- not active/active 63 [0x0020] = { txt = "Central Heating 2 mode", var = "CH2Mode" }, -- not active/active143 [0x0020] = { txt = "Central heating 2 mode", var = "CH2Mode" }, -- not active/active 64 144 [0x0040] = { txt = "Diagnostic indication", var = "DiagnosticEvent" } -- no diagnostics/diagnostics event 65 145 } 66 146 67 local otgFaultFlag_t = { -- ID 5: Application-specific fault flags (HB) 147 -- OpenTherm configuration flags [ID 3: master/slave config flags (HB)] 148 local 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)] 158 local otgFaultFlag_t = { 68 159 [0x0100] = { txt = "Service request", var = "FaultServiceRequest" }, 69 160 [0x0200] = { txt = "Lockout-reset", var = "FaultLockoutReset" }, … … 75 166 76 167 -- OpenTherm messages 77 78 168 local 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 (°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 (°C)", var = "f8.8" }, 178 [ 9] = { dir = "R-", txt = "Remote override room setpoint (°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 (°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 (°C)", val = "f8.8" }, 193 [24] = { dir = "-W", txt = "Room temperature (°C)", val = "f8.8", sid = OTG_TEMP_SENS_SID, var = "CurrentTemperature" }, 194 [25] = { dir = "R-", txt = "Boiler water temperature (°C)", val = "f8.8", var = "BoilerWaterTemperature" }, 195 [26] = { dir = "R-", txt = "Domestic hot water temperature (°C)", val = "f8.8", var = "DHWTemperature" }, 196 [27] = { dir = "R-", txt = "Outside temperature (°C)", val = "f8.8", var = "OutsideTemperature" }, 197 [28] = { dir = "R-", txt = "Return water temperature (°C)", val = "f8.8", var = "ReturnWaterTemperature" }, 198 [29] = { dir = "R-", txt = "Solar storage temperature (°C)", val = "f8.8" }, 199 [30] = { dir = "R-", txt = "Solar collector temperature (°C)", val = "s16" }, 200 [31] = { dir = "R-", txt = "Flow temperature central heating 2 (°C)", val = "f8.8" }, 201 [32] = { dir = "R-", txt = "Domestic hot water 2 temperature (°C)", val = "f8.8", var = "DHW2Temperature" }, 202 [33] = { dir = "R-", txt = "Boiler exhaust temperature (°C)", val = "s16" }, 203 [48] = { dir = "R-", txt = "Domestic hot water setpoint boundaries (°C)", val = "s8" }, 204 [49] = { dir = "R-", txt = "Max. central heating setpoint boundaries (°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 (°C)", val = "f8.8", var = "DHWSetpoint" }, 207 [57] = { dir = "RW", txt = "Max. central heating water setpoint (°C)", val = "f8.8", var = "MaxCHWaterSetpoint" }, 208 [58] = { dir = "RW", txt = "OTC heat curve ratio (°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 225 local 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]" } 126 232 } 127 233 … … 132 238 -- Update a system variable only if the value will change 133 239 function 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 139 247 end 140 248 return false … … 213 321 end 214 322 323 -- otgDecodeMessage 324 function 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 349 end 350 215 351 -- otgWriteCommand: write a command to the OTG 216 function otgWriteCommand(cmd )352 function otgWriteCommand(cmd, response) 217 353 local success = luup.io.write(cmd, otgDevice) 354 debug("Sent command " .. cmd) 218 355 if (success == false) then 219 356 otgMessage("Cannot send message to the OpenTherm Gateway", 2) 220 357 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) 221 366 end 222 367 end … … 265 410 end 266 411 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 271 419 end 272 420 273 421 -- Register luup web handlers 422 luup.register_handler("otgCallbackHandler", "GetMessages" .. otgDevice) 274 423 luup.register_handler("otgCallbackHandler", "GetConfiguration" .. otgDevice) 275 424 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) 276 446 end 277 447 … … 289 459 local msgVal = "flag8" 290 460 local msgVar = "" 461 local msgFlags = nil 291 462 if (otgMessage_t[msg] ~= nil) then 292 463 msgTxt = otgMessage_t[msg].txt 293 464 msgVal = otgMessage_t[msg].val or "flag8" 294 465 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 295 470 end 296 471 local val1 = tonumber("0x" .. string.sub(data, 6, 7)) … … 298 473 local val = 0 299 474 -- 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) 318 479 end 319 480 local s = string.format("%10s: %-14s %s = ", sender, ctype, msgTxt) .. val … … 321 482 debug(s) 322 483 -- Optional: decode flags 323 local flags = otgMessage_t[msg].flags324 484 val1 = val1 * 256 + val2 325 if ( flags ~= nil) then326 for i, item in pairs( flags) do485 if (msgFlags ~= nil) then 486 for i, item in pairs(msgFlags) do 327 487 local flagVal = ((bitw.band(val1, i) == 0) and "0" or "1") 328 488 debug(">> " .. item.txt .. ": " .. flagVal) … … 336 496 local sid = otgMessage_t[msg].sid or OTG_GATEWAY_SID 337 497 if (msgVal == "f8.8" and sid ~= OTG_GATEWAY_SID) then 498 val2 = string.format("%.1f", tonumber(val)) 338 499 updateIfNeeded(sid, msgVar, val2, otgDevice) -- use lower accuracy for non-gateway variables 339 500 sid = OTG_GATEWAY_SID -- set high accuray value in gateway variable as well 340 501 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 342 509 end 343 510 -- Optional: Update MCV specific vars … … 350 517 local modeState = "Idle" 351 518 local modeStatus = "Off" 352 if (chEnabled == true and chMode == true) then519 if (chEnabled == "1" and chMode == "1") then 353 520 modeState = "Heating" 354 521 modeStatus = "HeatOn" 355 elseif (chEnabled == true and chMode == false) then522 elseif (chEnabled == "1" and chMode == "0") then 356 523 modeState = "PendingHeat" 357 elseif (coolEnabled == true and coolMode == true) then524 elseif (coolEnabled == "1" and coolMode == "1") then 358 525 modeState = "Cooling" 359 526 modeStatus = "CoolOn" 360 elseif (coolEnabled == true and coolMode == false) then527 elseif (coolEnabled == "1" and coolMode == "0") then 361 528 modeState = "PendingCool" 362 529 end … … 364 531 updateIfNeeded(OTG_HVAC_USER_SID, "ModeStatus", modeStatus, otgDevice) 365 532 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 370 564 elseif (string.find(data, "Error") ~= nil) then -- Error received 371 local errNr = string.match(data, "(%d*)")565 local errNr = tonumber(string.match(data, "(%d+)")) 372 566 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) 373 572 else 374 573 debug("Unknown message") … … 377 576 end 378 577 379 -- Action functions578 --- ACTION FUNCTIONS --- 380 579 381 580 -- otgSetCurrentSetpoint 382 581 function otgSetCurrentSetpoint(NewCurrentSetpoint) 383 582 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 386 584 return otgWriteCommand("TT=" .. NewCurrentSetpoint) -- Temperature temporary 387 585 else 388 otgMessage("Set ModeTarget only possible in Gateway mode", 2)586 otgMessage("SetCurrentSetpoint only possible in Gateway mode", 2) 389 587 end 390 588 end … … 393 591 function otgSetModeTarget(NewModeTarget) 394 592 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 397 594 if (NewModeTarget == "Off") then 398 595 return otgWriteCommand("TT=0") -- Schedule … … 406 603 otgMessage("SetModeTarget only possible in Gateway mode", 2) 407 604 end 605 end 606 607 function 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 612 end 613 614 -- otgSetOutsideTemperature 615 function 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 622 end 623 624 -- otgSendCommand 625 function otgSendCommand(Command) 626 debug("otgSendCommand " .. (Command or "")) 627 return otgWriteCommand(Command, true) -- no checking on input 408 628 end 409 629 … … 481 701 debug("otgCallbackHandler: request " .. lul_request) 482 702 if (lul_outputformat ~= "xml") then 483 if (lul_request == "Get Configuration" .. otgDevice) then703 if (lul_request == "GetMessages" .. otgDevice) then 484 704 return table2Json(otgMessage_t) 705 elseif (lul_request == "GetConfiguration" .. otgDevice) then 706 return table2Json(otgConfig_t) 485 707 elseif (lul_request == "GetMessageFile" .. otgDevice) then 486 708 return dumpFile(otgLogFilename)
Note: See TracChangeset
for help on using the changeset viewer.