I’m new to all this but, managed to get my CurrentCost Energy Meter working with the Serial Binding in OH3. I hope it may be of use to others, also any advice on how to improve it would be greatly appreciated!
Things
Bridge serial:serialBridge:currentCost [serialPort="/dev/ttyUSB0", baudRate=57600] {
// Not using the serial device, I was hoping to sort the xml data here with
// regex instead of xpath in a rule, but could not get this to work,
// does anyone has any ideas?
//
// Thing serialDevice displayUnit [patternMatch=".*"] {
// Channels:
// Type string : test [transform="REGEX:(.*?)"]
}
currentcost.items
String CurrentCostRaw "CurrentCost XML [%s]" { channel="serial:serialBridge:currentCost:string" }
// Realtime energy usage
Number CurrentCostElectricTotalWatts "Usage now [%.0f W]" <energy>
String CurrentCostSoftwareVersion "Software version [%s]" <text>
Number CurrentCostDaysAlive "Age [%.0f days]" <time>
String CurrentCostLastUpdate "Last updated [%s]" <time>
Number CurrentCostTemperature "Temperature [%.1f °C]" <temperature>
Number CurrentCostDailyCost "Daily cost [£ %.2f]" <piggybank>
Number CurrentCostMonthlyCost "Monthly cost [£ %.2f]" <piggybank>
// Enable if 3 phase electric
// Number CurrentCostElectric1Watts "Electric 1 [%.0f W]"
// Number CurrentCostElectric1Watts "Electric 2 [%.0f W]"
// Number CurrentCostElectric1Watts "Electric 3 [%.0f W]"
// IAMs
Number CurrentCostIam1 "IAM 1 [%.0f W]" <poweroutlet_uk>
Number CurrentCostIam2 "IAM 2 [%.0f W]" <poweroutlet_uk>
Number CurrentCostIam3 "IAM 3 [%.0f W]" <poweroutlet_uk>
Number CurrentCostIam4 "IAM 4 [%.0f W]" <poweroutlet_uk>
Number CurrentCostIam5 "IAM 5 [%.0f W]" <poweroutlet_uk>
Number CurrentCostIam6 "IAM 6 [%.0f W]" <poweroutlet_uk>
Number CurrentCostIam7 "IAM 7 [%.0f W]" <poweroutlet_uk>
Number CurrentCostIam8 "IAM 8 [%.0f W]" <poweroutlet_uk>
Number CurrentCostIam9 "IAM 9 [%.0f W]" <poweroutlet_uk>
// Historic values
Number CurrentCostHistoricHour4 "2 to 4 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour6 "4 to 6 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour8 "6 to 8 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour10 "8 to 10 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour12 "10 to 12 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour14 "12 to 14 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour16 "14 to 16 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour18 "16 to 18 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour20 "18 to 20 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour22 "20 to 22 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricHour24 "22 to 24 hours ago [%.3f kW]" <line>
Number CurrentCostHistoricDay1 "1 day ago [%.3f kW]" <line>
Number CurrentCostHistoricDay2 "2 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay3 "3 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay4 "4 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay5 "5 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay6 "6 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay7 "7 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay8 "8 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay9 "9 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay10 "10 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay11 "11 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay12 "12 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay13 "13 days ago [%.3f kW]" <line>
Number CurrentCostHistoricDay14 "14 days ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth1 "1 month ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth2 "2 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth3 "3 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth4 "4 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth5 "5 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth6 "6 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth7 "7 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth8 "8 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth9 "9 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth10 "10 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth11 "11 months ago [%.3f kW]" <line>
Number CurrentCostHistoricMonth12 "12 months ago [%.3f kW]" <line>
currentcost.rule
// This rule updates currentcoast raw xml serial data
// Requres XPATH transformations
rule UpdateCurrentCost
when
Item CurrentCostRaw received update
then
// Code has been writted in accordance to the description
// issued 18th February 2009 at http://www.currentcost.com/cc128/xml.htm
var Number unitCost = 18.60 // pence cost per kw
for (String raw: CurrentCostRaw.state.toString.replace("</msg> <msg>","</msg>\r\n<msg>").split("\r\n"))
{
postUpdate(CurrentCostSoftwareVersion, transform("XPATH", "/msg/src/text()", raw))
postUpdate(CurrentCostDaysAlive, transform("XPATH", "/msg/dsb/text()", raw))
postUpdate(CurrentCostLastUpdate, transform("XPATH", "/msg/time/text()", raw))
// If Xml contains real-time data
if ( transform("XPATH", "boolean(/msg/type[text() = '1'])", raw) == "true" ) {
postUpdate(CurrentCostTemperature, transform("XPATH", "/msg/tmpr/text()", raw))
// if sensor = 0 then whole house electricty
if ( transform("XPATH", "/msg/sensor", raw) == "0" ) {
// Uncomment lines below if you use 3 phase electric UNTESTED
// postUpdate(CurrentCostElectric1Watts, transform("XPATH", "/msg/ch1/watts",raw))
// postUpdate(CurrentCostElectric2Watts, transform("XPATH", "/msg/ch2/watts",raw))
// postUpdate(CurrentCostElectric3Watts, transform("XPATH", "/msg/ch3/watts",raw))
// var Number totalWatts = Integer::parseInt(transform("XPATH", "<?sum(./msg/ch1/watts | ./msg/ch2/watts | ./msg/ch3/watts)?>"))
var Number totalWatts = Integer::parseInt(transform("XPATH", "/msg/ch1/watts/text()",raw))
postUpdate( CurrentCostElectricTotalWatts, totalWatts )
postUpdate( CurrentCostDailyCost, totalWatts * 24 / 1000 * unitCost / 100 )
postUpdate( CurrentCostMonthlyCost, totalWatts * 24 / 1000 * unitCost / 100 * 30.436875)
}
// else log IAMs response
else if ( transform("XPATH", "/msg/sensor", raw) == "1" ) { postUpdate(CurrentCostIam1, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else if ( transform("XPATH", "/msg/sensor", raw) == "2" ) { postUpdate(CurrentCostIam2, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else if ( transform("XPATH", "/msg/sensor", raw) == "3" ) { postUpdate(CurrentCostIam3, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else if ( transform("XPATH", "/msg/sensor", raw) == "4" ) { postUpdate(CurrentCostIam4, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else if ( transform("XPATH", "/msg/sensor", raw) == "5" ) { postUpdate(CurrentCostIam5, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else if ( transform("XPATH", "/msg/sensor", raw) == "6" ) { postUpdate(CurrentCostIam6, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else if ( transform("XPATH", "/msg/sensor", raw) == "7" ) { postUpdate(CurrentCostIam7, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else if ( transform("XPATH", "/msg/sensor", raw) == "8" ) { postUpdate(CurrentCostIam8, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else if ( transform("XPATH", "/msg/sensor", raw) == "9" ) { postUpdate(CurrentCostIam9, transform("XPATH", "/msg/ch1/watts/text()",raw)) }
else { logInfo("CurrentCost","[Realtime XML not processed - " + raw + "]") }
}
// Historical
else if ( transform("XPATH", "boolean(/msg/hist)",raw) == "true" ) {
// BI-HOURLYS
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h002)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour2, transform("XPATH", "/msg/hist/data[sensor='0']/h002/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h004)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour4, transform("XPATH", "/msg/hist/data[sensor='0']/h004/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h006)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour6, transform("XPATH", "/msg/hist/data[sensor='0']/h006/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h008)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour8, transform("XPATH", "/msg/hist/data[sensor='0']/h008/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h010)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour10, transform("XPATH", "/msg/hist/data[sensor='0']/h010/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h012)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour12, transform("XPATH", "/msg/hist/data[sensor='0']/h012/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h014)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour14, transform("XPATH", "/msg/hist/data[sensor='0']/h014/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h016)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour16, transform("XPATH", "/msg/hist/data[sensor='0']/h016/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h018)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour18, transform("XPATH", "/msg/hist/data[sensor='0']/h018/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h020)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour20, transform("XPATH", "/msg/hist/data[sensor='0']/h020/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h022)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour22, transform("XPATH", "/msg/hist/data[sensor='0']/h022/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/h024)", raw) == "true" ) { postUpdate(CurrentCostHistoricHour24, transform("XPATH", "/msg/hist/data[sensor='0']/h024/text()",raw)) }
// DAYS
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d001)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay1, transform("XPATH", "/msg/hist/data[sensor='0']/d001/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d002)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay2, transform("XPATH", "/msg/hist/data[sensor='0']/d002/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d003)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay3, transform("XPATH", "/msg/hist/data[sensor='0']/d003/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d004)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay4, transform("XPATH", "/msg/hist/data[sensor='0']/d004/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d005)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay5, transform("XPATH", "/msg/hist/data[sensor='0']/d005/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d006)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay6, transform("XPATH", "/msg/hist/data[sensor='0']/d006/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d007)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay7, transform("XPATH", "/msg/hist/data[sensor='0']/d007/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d008)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay8, transform("XPATH", "/msg/hist/data[sensor='0']/d008/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d009)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay9, transform("XPATH", "/msg/hist/data[sensor='0']/d009/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d010)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay10, transform("XPATH", "/msg/hist/data[sensor='0']/d010/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d011)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay11, transform("XPATH", "/msg/hist/data[sensor='0']/d011/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d012)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay12, transform("XPATH", "/msg/hist/data[sensor='0']/d012/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d013)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay13, transform("XPATH", "/msg/hist/data[sensor='0']/d013/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/d014)", raw) == "true" ) { postUpdate(CurrentCostHistoricDay14, transform("XPATH", "/msg/hist/data[sensor='0']/d014/text()",raw)) }
// MONTHS
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m001)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth1, transform("XPATH", "/msg/hist/data[sensor='0']/m001/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m002)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth2, transform("XPATH", "/msg/hist/data[sensor='0']/m002/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m003)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth3, transform("XPATH", "/msg/hist/data[sensor='0']/m003/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m004)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth4, transform("XPATH", "/msg/hist/data[sensor='0']/m004/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m005)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth5, transform("XPATH", "/msg/hist/data[sensor='0']/m005/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m006)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth6, transform("XPATH", "/msg/hist/data[sensor='0']/m006/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m007)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth7, transform("XPATH", "/msg/hist/data[sensor='0']/m007/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m008)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth8, transform("XPATH", "/msg/hist/data[sensor='0']/m008/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m009)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth9, transform("XPATH", "/msg/hist/data[sensor='0']/m009/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m010)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth10, transform("XPATH", "/msg/hist/data[sensor='0']/m010/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m011)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth11, transform("XPATH", "/msg/hist/data[sensor='0']/m011/text()",raw)) }
if ( transform("XPATH", "boolean(/msg/hist/data[sensor='0']/m012)", raw) == "true" ) { postUpdate(CurrentCostHistoricMonth12, transform("XPATH", "/msg/hist/data[sensor='0']/m012/text()",raw)) }
}
else { logInfo("CurrentCost","[XML UNKNOWN - " + raw + "]") }
}
end
Sitemap
// Current Cost Energy Monitor
Text item=CurrentCostElectricTotalWatts label="Energy Usage" icon="energy" {
Frame{
Text item=CurrentCostElectricTotalWatts
Text item=CurrentCostDailyCost
Text item=CurrentCostMonthlyCost
Text item=CurrentCostLastUpdate
Text item=CurrentCostTemperature
Text item=CurrentCostDaysAlive
Text item=CurrentCostSoftwareVersion
}
Frame label="Individual Appliance Monitors" {
Text item=CurrentCostIam1
Text item=CurrentCostIam2
Text item=CurrentCostIam3
//Text item=CurrentCostIam4
//Text item=CurrentCostIam5
//Text item=CurrentCostIam6
//Text item=CurrentCostIam7
//Text item=CurrentCostIam8
//Text item=CurrentCostIam9
}
Frame label="Historic Bi-hourly Usage" {
Text item=CurrentCostHistoricHour4
Text item=CurrentCostHistoricHour6
Text item=CurrentCostHistoricHour8
Text item=CurrentCostHistoricHour10
Text item=CurrentCostHistoricHour12
Text item=CurrentCostHistoricHour14
Text item=CurrentCostHistoricHour16
Text item=CurrentCostHistoricHour18
Text item=CurrentCostHistoricHour20
Text item=CurrentCostHistoricHour22
Text item=CurrentCostHistoricHour24
}
Frame label="Historic Day Usage" {
Text item=CurrentCostHistoricDay1
Text item=CurrentCostHistoricDay2
Text item=CurrentCostHistoricDay3
Text item=CurrentCostHistoricDay4
Text item=CurrentCostHistoricDay5
Text item=CurrentCostHistoricDay6
Text item=CurrentCostHistoricDay7
Text item=CurrentCostHistoricDay8
Text item=CurrentCostHistoricDay9
Text item=CurrentCostHistoricDay10
Text item=CurrentCostHistoricDay11
Text item=CurrentCostHistoricDay12
Text item=CurrentCostHistoricDay13
Text item=CurrentCostHistoricDay14
}
Frame label="Historic Month Usage" {
Text item=CurrentCostHistoricMonth1
Text item=CurrentCostHistoricMonth2
Text item=CurrentCostHistoricMonth3
Text item=CurrentCostHistoricMonth4
Text item=CurrentCostHistoricMonth5
Text item=CurrentCostHistoricMonth6
Text item=CurrentCostHistoricMonth7
Text item=CurrentCostHistoricMonth8
Text item=CurrentCostHistoricMonth9
Text item=CurrentCostHistoricMonth10
Text item=CurrentCostHistoricMonth11
Text item=CurrentCostHistoricMonth12
}
}
It all seems to be working ok, the only issue is that sometimes the rule drops into XML not recognised catches and when I inspect the XML I just can’t work out why the XPATH is not parsing it. It only happens now and then, so no biggy, it just bugs me! If you have any ideas then please let me know.
Thanks.