Forum user ravedog asked that I post the "behind the scenes" portion of what drives my HTML formatted daily report. Here goes...
First here is a PDF of a report, unfortunately, I picked a boring day and there are more 0's than usual and my CAI webcontrol board seems to have died last week resulting in no laundry monitoring and broken temperature values but it still gives you an idea:
XathHome Daily Report - 2014-08-27.pdf
Here is the same thing in a loooooong jpg file:
Note: the narrow width was chosen as I usually read these on my phone and this fits nicely.
Here is the HTML code that I use in the custom notification:
<html>
<body>
<table width=442 bgcolor=AAAAAAS border=0>
<tr><td align=center>
<img src="http://<internet-facing-webserver>/images/XathHome_sm.jpg">
<h3>XathHome Daily Report for ${alert.date}</h3>
Mid Session Report
<align=left>
<hr width=440>
<table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Garage Door Stats</b></td></tr>
<tr><td>
<table width=440 border="1" bgcolor=AAAAAF>
<tr align=center><td><b>Door</b></td><td><b>Opened</b></td><td><b>Closed</b></td></tr>
<tr><td><b>Dad's Door</td><td align=center>${var.1.1}</td><td align=center>${var.1.2}</td></tr>
<tr><td><b>Mom's Door</td><td align=center>${var.1.8}</td><td align=center>${var.1.9}</td></tr></table>
</td></tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Lighting Stats</b></td></tr>
<tr><td>
<table width=440 border="1" bgcolor=AAAAAF>
<tr align=center><td><b>Device</b></td><td><b>On Count</b></td><td><b>Auto Off Count</b></td></tr>
<tr><td><b>Kitchen Counter</b></td><td align=center>${var.1.60}</td><td align=center>${var.1.61}</td></tr>
<tr><td><b>Kitchen Island</b></td><td align=center>${var.1.58}</td><td align=center>${var.1.59}</td></tr>
<tr><td><b>Dining Room</b></td><td align=center>${var.1.62}</td><td align=center>${var.1.63}</td></tr>
<tr><td><b>Living Room</b></td><td align=center>${var.1.64}</td><td align=center>${var.1.65}</td></tr>
<tr><td><b>Main Bath</b></td><td align=center>${var.1.21}</td><td align=center>${var.1.22}</td></tr>
<tr><td><b>Basement Stairs</b></td><td align=center>${var.1.10}</td><td align=center>${var.1.3}</td></tr>
<tr><td><b>Utility Room</b></td><td align=center>${var.1.12}</td><td align=center>${var.1.4}</td></tr>
<tr><td><b>Alyssa's Room</b></td><td align=center>${var.1.11}</td><td align=center>${var.1.5}</td></tr>
<tr><td><b>Back Porch</b></td><td align=center>${var.1.14}</td><td align=center>${var.1.7}</td></tr>
<tr><td><b>Garage Lights</b></td><td align=center>${var.1.13}</td><td align=center>${var.1.6}</td></tr>
<tr><td><b>Shop Lights</b></td><td align=center>${var.1.15}</td><td align=center>${var.1.16}</td></tr>
<tr><td><b>Barn Lights</b></td><td align=center>${var.1.26}</td><td align=center>${var.1.27}</td></tr>
<tr><td><b>Barn Floods</b></td><td align=center>${var.1.24}</td><td align=center>${var.1.25}</td></tr>
</table></td></tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td><table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Current Toggle Status</b></td></tr>
<tr><td><table width=440 border="1" bgcolor=AAAAAF>
<tr align=center><td><b>Item</b></td><td><b>Value</b></td></tr>
<tr><td><b>Garage Door Notify</b></td><td align=center>${var.2.1}</td></tr>
<tr><td><b>AutoTimers</b></td><td align=center>${var.2.3}</td></tr>
<tr><td><b>Rhino Charger</b></td><td align=center>${var.2.12}</td></tr>
<tr><td><b>Internet Up Test</b></td><td align=center>${var.2.7}</td></tr>
<tr><td><b>Network Filter</b></td><td align=center>${var.1.36}</td></tr>
</table></tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Motion Stats</b></td></tr>
<tr><td><table width=440 border="1" bgcolor=AAAAAF>
<tr align=center><td><b>Item</b></td><td><b>Value</b></td></tr>
<tr><td><b>Shop Motion Count</b></td><td align=center>${var.1.19}</td></tr>
<tr><td><b>Basement Motion Count</b></td><td align=center>${var.1.31}</td></tr>
<tr><td><b>Garage Motion Count</b></td><td align=center>${var.1.30}</td></tr>
<tr><td><b>LivingRm Motion Count</b></td><td align=center>${var.1.32}</td></tr>
</table></tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Security Stats</b></td></tr>
<tr><td><table width=440 border="1" bgcolor=AAAAAF>
<tr align=center><td><b>Item</b></td><td><b>Value</b></td></tr>
<tr><td><b>Shop Breached</b></td><td align=center><font color="red">${var.1.48}</font></td></tr>
<tr><td><b>House Breached</b></td><td align=center><font color="red">${var.1.49}</font></td></tr>
<tr><td><b>Home/Away</b></td><td align=center>${var.1.23}</td></tr>
<tr><td><b>Shop Security</b></td><td align=center>${var.1.20}</td></tr>
</table></tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Rhino Charger</b></td></tr>
<tr><td><table width=440 border=1 bgcolor=AAAAAF>
<tr><td><b>Cycled</b></td><td align=center>${var.1.40}</td></tr></table></td></tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Network Stats</b></td></tr>
<tr><td><table width=440 border=1 bgcolor=AAAAAF>
<tr><td><b>Network Uplink Failed</b></td><td align=center>${var.1.66}</td></tr></table></td></tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Environmental Sensors</b></td></tr>
<tr><td><table width=440 border="1" bgcolor=AAAAAF>
<tr align=center><td><b>Location</b></td><td><b>Temp</b></td><td><b>Low</b></td><td><b>High</b></td></tr>
<tr><td><b>Basement</td><td align=center>${var.1.38}</td><td align=center><font color="blue">${var.1.42}</font></td><td align=center><font color="red">${var.1.43}</font></td></tr>
<tr><td><b>Outside</td><td align=center>${var.1.39}</td><td align=center><font color="blue">${var.1.44}</font></td><td align=center><font color="red">${var.1.45}</font></td></tr>
<tr><td><b>Hot Water</td><td align=center>${var.1.41}</td><td align=center><font color="blue">${var.1.46}</font></td><td align=center><font color="red">${var.1.47}</font></td></tr></table>
</tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=440 Border=1 bgcolor=AAAA80>
<tr align=center><td><b>Occupancy Stats</b></td></tr>
<tr><td><table width=440 border="1" bgcolor=AAAAAF>
<tr align=center><td><b>Statistic</b></td><td><b>Time</b></td></tr>
<tr><td><b>Occupied</td><td align=center>${var.1.52}:${var.1.53}</td></tr>
<tr><td><b>Vacant</td><td align=center>${var.1.54}:${var.1.55}</td></tr>
<tr><td><b>Occ/Vac Cycles</td><td align=center>${var.1.57}</td></tr></table>
</tr></table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=440 border=1 bgcolor=AAAA80>
<tr align=center><td><b>Sunrise</b></td><td><b>Sunset</b></td></tr>
<tr align=center><td><font color="blue">${sys.sunrise12}</font></td><td><font color="red">${sys.sunset24}</font></td></tr>
</table>
</td></tr>
<tr><td><hr width=440 align=left></td></tr>
<tr><td>
<table width=400 border=0><tr><td align=center>~ ~ ~ END OF REPORT ~ ~ ~</td></tr>
<tr align=center><td><font color="green"><i>Report Generated: ${sys.time12} ${sys.date}</i></font></td></tr>
<tr align=center><td><a href="http://<my-web-server-ip-address>/isylogs">View Log Files</a></td></tr></table>
</align>
</td></tr></table>
</body></html>
As you can see, it's just a bunch of nested tables with hard coded text and ISY substitution variables. The notification is set to HTML mode obviously.
For the tracing of the data, I have a number of programs that just count things like controls being turned On manually or turned off automatically, garage doors opening and closing etc. For this I use integer variables and a number of programs like:
If
Status 'Basement / Alyssa's Room / Alyssa's Room' is On
Then
$i.cnt.AlyssaLightsOn += 1
$i.cnt.AlyssaLightsOn Init To $i.cnt.AlyssaLightsOn
Resource 'Syslog-LIGTNG - Alyssa's Room On'
Else
- No Actions - (To add one, press 'Action')
and:
If
Status 'Basement / Alyssa's Room / Alyssa's Room' is On
Then
Wait 10 minutes
Set Scene 'Basement / Alyssa's Room / Alyssa's Room' Off
$i.cnt.AlyssaLighsOff += 1
$i.cnt.AlyssaLighsOff Init To $i.cnt.AlyssaLighsOff
Resource 'Syslog-LIGTNG - Alyssa's Room AutoOff'
Else
- No Actions - (To add one, press 'Action')
For things with times like pellet stove runtime or occupancy I count minutes while a condition is true like:
If
$s.PelletStoveRunning is 1
Then
Wait 1 minute
Repeat Every 1 minute
$i.time.PelletRun += 1
$i.time.PelletRun Init To $i.time.PelletRun
Else
- No Actions - (To add one, press 'Action')
or:
If
$s.sec.Occupancy is 0
Then
Wait 1 minute
Repeat Every 1 minute
$i.time.Vacant += 1
$i.time.Vacant Init To $i.time.Vacant
Else
Wait 1 minute
Repeat Every 1 minute
$i.time.Occupied += 1
$i.time.Occupied Init To $i.time.Occupied
Then when its time to report, I generate hrs/mins out of the above counters as follows:
If
- No Conditions - (To add one, press 'Schedule' or 'Condition')
Then
$i.time.OccupiedHrs = $i.time.Occupied
$i.time.OccupiedHrs /= 60
$i.calc.temporary = $i.time.OccupiedHrs
$i.calc.temporary *= 60
$i.time.OccupiedMins = $i.time.Occupied
$i.time.OccupiedMins -= $i.calc.temporary
$i.time.VacantHrs = $i.time.Vacant
$i.time.VacantHrs /= 60
$i.calc.temporary = $i.time.VacantHrs
$i.calc.temporary *= 60
$i.time.VacantMins = $i.time.Vacant
$i.time.VacantMins -= $i.calc.temporary
Else
- No Actions - (To add one, press 'Action')
Then call the report after a delay to ensure the calculations have been completed before reporting, then delay to alow time for the notification to send, then reset the daily counters:
If
Time is 11:58:30PM
Then
Run Program 'Calc_Occ/Vac_Hrs.Mins' (Then Path)
Wait 2 seconds
Run Program 'Calc_PelletStoveRun_Hrs.Mins' (Then Path)
Wait 2 seconds
Send Notification to 'Xathros Email' content 'DailyReport'
Wait 1 minute and 27 seconds
$i.cnt.AlyssaLighsOff = 0
$i.cnt.AlyssaLighsOff Init To 0
$i.cnt.AlyssaLightsOn = 0
$i.cnt.AlyssaLightsOn Init To 0
$i.cnt.BackPorchLighsOff = 0
$i.cnt.BackPorchLighsOff Init To 0
$i.cnt.BasementLightsOff = 0
$i.cnt.BasementLightsOff Init To 0
$i.cnt.GarageLighsOff = 0
$i.cnt.GarageLighsOff Init To 0
$i.cnt.UtilityLightsOff = 0
$i.cnt.UtilityLightsOff Init To 0
$i.cnt.ShopLightsOff = 0
$i.cnt.ShopLightsOff Init To 0
$i.Dad_GDC = 0
$i.Dad_GDC Init To 0
$i.Dad_GDO = 0
$i.Dad_GDO Init To 0
$i.Mom_GDC = 0
$i.Mom_GDC Init To 0
$i.Mom_GDO = 0
$i.Mom_GDO Init To 0
$i.cnt.BackPorchLightsOn = 0
$i.cnt.BackPorchLightsOn Init To 0
$i.cnt.BasementLightsOn = 0
$i.cnt.BasementLightsOn Init To 0
$i.cnt.GarageLightsOn = 0
$i.cnt.GarageLightsOn Init To 0
$i.cnt.UtilityLightsOn = 0
$i.cnt.UtilityLightsOn Init To 0
$i.cnt.ShopLightsOn = 0
$i.cnt.ShopLightsOn Init To 0
$i.cnt.MainBathAutoOff = 0
$i.cnt.MainBathAutoOff Init To 0
$i.cnt.MainBathOn = 0
$i.cnt.MainBathOn Init To 0
$i.cnt.BarnFloodsAutoOff = 0
$i.cnt.BarnFloodsAutoOff Init To 0
$i.cnt.BarnFloodsOn = 0
$i.cnt.BarnFloodsOn Init To 0
$i.cnt.BarnLightsAutoOff = 0
$i.cnt.BarnLightsAutoOff Init To 0
$i.cnt.BarnLightsOn = 0
$i.cnt.BarnLightsOn Init To 0
$i.cnt.BasementMotion = 0
$i.cnt.BasementMotion Init To 0
$i.cnt.GarageMotion = 0
$i.cnt.GarageMotion Init To 0
$i.cnt.LRMotion = 0
$i.cnt.LRMotion Init To 0
$i.cnt.ShopMotion = 0
$i.cnt.ShopMotion Init To 0
$i.cnt.RhinoChargerCycle = 0
$i.cnt.RhinoChargerCycle Init To 0
$i.cnt.OccupancyCnt = 0
$i.cnt.OccupancyCnt Init To 0
$i.time.Occupied = 0
$i.time.Occupied Init To 0
$i.time.Vacant = 0
$i.time.Vacant Init To 0
$i.time.PelletRun = 0
$i.time.PelletRun Init To 0
$i.cnt.DiningRmOff = 0
$i.cnt.DiningRmOff = 0
$i.cnt.DiningRmOn = 0
$i.cnt.DiningRmOn Init To 0
$i.cnt.KitCntrOff = 0
$i.cnt.KitCntrOff Init To 0
$i.cnt.KitCntrOn = 0
$i.cnt.KitCntrOn Init To 0
$i.cnt.KitIslandOff = 0
$i.cnt.KitIslandOff Init To 0
$i.cnt.KitIslandOn = 0
$i.cnt.KitIslandOn Init To 0
$i.cnt.LivngRmOff = 0
$i.cnt.LivngRmOff Init To 0
$i.cnt.LivngRmOn = 0
$i.cnt.LivngRmOn Init To 0
$i.sec.ShopBreachedCount = 0
$i.sec.ShopBreachedCount Init To 0
$i.sec.HouseBreachedCount = 0
$i.sec.HouseBreachedCount Init To 0
$i.cnt.NetworkFailed Init To 0
$i.cnt.NetworkFailed = 0
$i.cnt.UpstairsBathAutoOff = 0
$i.cnt.UpstairsBathAutoOff Init To 0
$i.cnt.UpstairsBathOn = 0
$i.cnt.UpstairsBathOn Init To 0
$i.cnt.GirlsRoomOn = 0
$i.cnt.GirlsRoomOn Init To 0
$i.cnt.BoysRoomOn = 0
$i.cnt.BoysRoomOn Init To 0
$i.cnt.PelletStoveCycled = 0
$i.cnt.PelletStoveCycled Init To 0
$i.cnt.FurnaceCycled = 0
$i.cnt.FurnaceCycled Init To 0
$i.cnt.BreezewayAutoOff = 0
$i.cnt.BreezewayAutoOff Init To 0
$i.cnt.BreezewayOn = 0
$i.cnt.BreezewayOn Init To 0
$i.cnt.FrontEntryOff = 0
$i.cnt.FrontEntryOff Init To 0
$i.cnt.FrontEntryOn = 0
$i.cnt.FrontEntryOn Init To 0
$i.cnt.FrontHallAutoOff = 0
$i.cnt.FrontHallAutoOff Init To 0
$i.cnt.FrontHallOn = 0
$i.cnt.FrontHallOn Init To 0
$i.cnt.FrontPorchAutoOff = 0
$i.cnt.FrontPorchAutoOff Init To 0
$i.cnt.FrontPorchOn = 0
$i.cnt.FrontPorchOn Init To 0
$i.cnt.MasterBedMotion Init To 0
$i.cnt.MasterBedMotion = 0
$i.cnt.KaysRoomMotion = 0
$i.cnt.KaysRoomMotion Init To 0
$i.cnt.GirlsRoomMotion = 0
$i.cnt.GirlsRoomMotion Init To 0
$i.cnt.BoysRoomMotion = 0
$i.cnt.BoysRoomMotion Init To 0
$i.cnt.DryerCount = 0
$i.cnt.DryerCount Init To 0
$i.cnt.WashCount = 0
$i.cnt.WashCount Init To 0
Run Program 'ResetHiLowTemps' (Then Path)
Else
- No Actions - (To add one, press 'Action')
Other things to consider:
Images need to be hosted somewhere as the ISY has no ability to deal with them. In my case, I placed the image of my house on the webserver where my blog lives as that is accessable from most anywhere. My log files linked at the bottom of the report live on the web server on one of my Raspberry Pi's and is only accessable when on my lan. This was by choice.
Currently formatting things is difficult but I expect that with the V5.x firmwares we may gain more capabilities and this all may become much easier.
Thats it in a rather large nutshell. Hope somebody finds all of this of some value.
-Xathros