Jump to content

HTML Formatted custom notifications


Xathros

Recommended Posts

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:

post-1150-0-45376600-1409250781_thumb.jpg

 

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

Link to comment

Nice! As I've gotten experience with my ISY I've been looking forward to some kind of dashboard for my house. I'm interested in reporting sprinkler routines, use of particular lights and devices, and furnaces/AC run time. I can use this as a template to arrive at a similar destination.

 

I like the top to bottom approach you used. Also all of the little things like hosting images, etc.

 

Thank you Xathros

Link to comment

Holy crap. Awesome. Loving it. It tickles my OCD funnybone something fierce. I'd love to implement some of this tracking myself. Thanks for sharing this.

 

 

Sent from my iPad using Tapatalk

Link to comment

Nice! As I've gotten experience with my ISY I've been looking forward to some kind of dashboard for my house. I'm interested in reporting sprinkler routines, use of particular lights and devices, and furnaces/AC run time. I can use this as a template to arrive at a similar destination.

 

I like the top to bottom approach you used. Also all of the little things like hosting images, etc.

 

Thank you Xathros

 

 

Holy crap. Awesome. Loving it. It tickles my OCD funnybone something fierce. I'd love to implement some of this tracking myself. Thanks for sharing this.

 

 

Sent from my iPad using Tapatalk

 

No problem.  As always, happy to help.

 

-Xathros

Link to comment

Thanks for the write up. It's given me lots of ideas. It's really great to see what other people are doing.

 

Could you perhaps explain a bit about how you are doing your logging. You mention it's stored on one of your Pi's.

 

Peter.

Hi Peter-

 

It depends what portion of my logging you are referring to.  I run a syslog server on my Pi.  I have the syslog from my DD-WRT router directed there, the Pi's own logs are there and I write to an ISY log on the Pi using network resources called by programs.  Here is an excerpt from todays ISY log:

ISY994i - SECRTY - Breezeway Entry  Door Closed.
ISY994i - MOTION - Living Room
ISY994i - OCPNCY - Matt iPhone Online.
ISY994i - OCPNCY - Jess iPhone Online.
ISY994i - MOTION - Living Room
ISY994i - MOTION - Living Room
ISY994i - MOTION - Living Room
ISY994i - MOTION - Living Room
ISY994i - SECRTY - Breezeway Entry  Door Opened.
ISY994i - OCPNCY - Control Event Detected.
ISY994i - SECRTY - Breezeway Entry  Door Opened.
ISY994i - OCPNCY - Control Event Detected.
ISY994i - SECRTY - Breezeway Entry  Door Closed.
ISY994i - LIGTNG - Utility Room AutoOff.
ISY994i - MOTION - Living Room
ISY994i - MOTION - Living Room
ISY994i - MOTION - Living Room
ISY994i - MOTION - Living Room
ISY994i - MOTION - Master Bed
ISY994i - MOTION - Master Bed
ISY994i - OCPNCY - Matt iPhone Online.
ISY994i - OCPNCY - Jess iPhone Online.
ISY994i - LIGTNG - Main Bath Off.
ISY994i - OCPNCY - Matt iPhone Online.
ISY994i - OCPNCY - Jess iPhone Online.
ISY994i - PRXMTY - Jess' iPhone Disconnected.
ISY994i - OCPNCY - Matt iPhone Online.
ISY994i - PRXMTY - Matt's iPhone Disconnected.
ISY994i - NETWRK - Internet Access Test Started.
ISY994i - NETWRK - Internet Access Test Passed.
ISY994i - PRXMTY - Matt's iPhone Connected.
ISY994i - OCPNCY - Matt iPhone Online.
ISY994i - PRXMTY - Lora's iPhone Connected.
ISY994i - PRXMTY - Livvy's iPhone Connected.
ISY994i - SECRTY - Breezeway Entry Access Code 3 - Livvy
ISY994i - OCPNCY - Control Event Detected.
ISY994i - SECRTY - Breezeway Entry  Door Opened.
ISY994i - OCPNCY - Control Event Detected.
ISY994i - SECRTY - Breezeway Entry  Door Closed.
ISY994i - MOTION - Living Room

The network resource for these is fairly simple:

post-1150-0-28222500-1409255160_thumb.jpg

 

I had to create a Source, Filter and Destination in my syslog-ng config on the Pi to look for the ISY entries coming in via UDP from the ISY's IP address and to point them to an appropriately named log file.  I also set up a cron job to rename and move the log files into the webserver's directory daily to make them available via the link at the bottom of my report..

 

The logging of control data as shown in the daily report is described in my first post.  I'm simply incrementing integer variables as control events happen then dump those values into the report at the end of the day.

 

Hope that answers the question.

 

-Xathros

 

EDIT: The log above normally contains a date/time stamp as well as the IP address of my ISY, I removed those before posting.  Should have left the time stamp...

Link to comment

Archived

This topic is now archived and is closed to further replies.


×
×
  • Create New...