Show Current Sun Position and Shadow of House (Generate SVG)

I’ve created a small python script that generates and SVG image to illustrate where the sun is currently positioned and which side of the house is facing the sun.

I wire the script up with a rule when the sun’s azimuth changes and then I include the SVG in my HABPanel like this:

It’s not very useful, but it looks cool on my HABPanel :slight_smile:

Note, the script relies on InfluxDb as the persistence layer to retrieve the last days azimuth values per hour, etc.

It also requires the Astro binding and the following items:

Number   Sun_Azimuth            "Sun Azimuth"                { channel="astro:sun:local:position#azimuth" }
Number   Sun_Elevation          "Sun Elevation"              { channel="astro:sun:local:position#elevation" }
Number	 Sunrise_Azimuth
Number	 Sunset_Azimuth

This is the rule to capture the sun’s azimuth during sunset and sunrise and refreshes the SVG with every azimuth change:

rule "Shaddow SVG"
when
    Item Sun_Azimuth received update
then

        val resp =  executeCommandLine("/usr/bin/python /etc/openhab2/scripts/shaddow.py update", 10000)
        logInfo("Shaddow", "Updating Shaddow SVG")          
        logInfo("Shaddow", resp)          

end

rule "Sunset Rule"
when
    Channel 'astro:sun:local:set#event' triggered START 
then

    postUpdate(Sunset_Azimuth,Sun_Azimuth.state)    
    logInfo("Shaddow","Setting Sunset Azimuth.")

end

rule "Sunrise Rule"
when
    Channel 'astro:sun:local:rise#event' triggered START 
then

    postUpdate(Sunrise_Azimuth,Sun_Azimuth.state)    
    logInfo("Shaddow","Setting Sunrise Azimuth.")

end

Once set up, you need to specify the shape of your house in 100 x 100 unit square at the top of the python file, for my house it’s:

# Shape of the house in a 100 by 100 units square
SHAPE = [{'x': 60.04, 'y': 12.52}, \
		{'x': 89.15, 'y': 37.66}, \
		{'x': 84.24, 'y': 43.36}, \
		{'x': 87.19, 'y': 45.91}, \
		{'x': 66.21, 'y': 70.02}, \
		{'x': 63.15, 'y': 67.56}, \
		{'x': 45.94, 'y': 87.48}, \
		{'x': 32.70, 'y': 76.04}, \
		{'x': 31.09, 'y': 77.90}, \
		{'x': 10.85, 'y': 60.42}, \
		{'x': 45.44, 'y': 20.36}, \
		{'x': 49.93, 'y': 24.23}]

You can change the colors and filename in the pything script.

Scripts:

myopenhab.py
shaddow.py

To add to HABPanel:

Add a template widget with this content:

<object data="/static/matrix-theme/shaddow.svg?{{itemValue('Sun_Azimuth')}}" type="image/svg+xml"></object>      

The ?{{itemValue(‘Sun_Azimuth’)}} ensures that the SVG gets refreshed automatically as the azimuth changes.

60 Likes

how do you calculate water consumption?

Sorry, that’s a different widget, unrelated to this thread.

I use Smappee as the sensor.

never heard, cool. How you find it, reliable?

I’ve used it for energy monitoring for a few months now and it works great. I just started with the water sensor a week ago. It depends very much on your water meter but so far so good for me.

I’d disagree! I’ve setup rules for blinds (which I currently do not have) that open or close depending on sun position. This is a great visible representation to show what is happening.

Nice one!

2 Likes

Hey @pmpkk :wave:

Your scripts work great, thank you!
I’ve added some improvements - if you’re launching it for the first time, there are errors because Sunrise_Azimuth and Sunset_Azimuth are NULL.
I’ve fixed it this way:

        self.oh = openhab()
        self.azimuth = float(self.oh.getState('Sun_Azimuth'))
        self.elevation = float(self.oh.getState('SunElevation'))
        self.sr = self.oh.getState('Sunrise_Azimuth')
        self.ss = self.oh.getState('Sunset_Azimuth')
        self.sunrise_azimuth = float(self.sr) if self.sr != 'NULL' else 0
        self.sunset_azimuth = float(self.ss) if self.ss != 'NULL' else 0
        ts = time.time()

Also on my Raspberry PI I’ve got permission errors when openHAB tried to write to the file that’s non-existent.
To avoid that, I created an empty shaddow.svg file and made it writable:

[17:46:21] blabla@XXXX:/etc/openhab2/html/matrix-theme$ chmod 666 shaddow.svg

Fantastic piece of work!
Thank you :slight_smile:

5 Likes

Very well written tutorial. Thank you for contributing!

Hello! An interesting idea!
I do not understand the python, help me understand, I have such a log:

2017-10-04 11:39:23.046 [INFO ] [lipse.smarthome.model.script.Shaddow] - Updating Shaddow SVG
2017-10-04 11:39:23.048 [INFO ] [lipse.smarthome.model.script.Shaddow] - Successfully got state from OpenHab: sun_azimuth
Successfully got state from OpenHab: sun_elevation
Successfully got state from OpenHab: sun_rise_azimuth
Successfully got state from OpenHab: sun_set_azimuth
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-02T16:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-02T17:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-02T18:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-02T19:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-02T20:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-02T21:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-02T22:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-02T23:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T00:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T01:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T02:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T03:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T04:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T05:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T06:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T07:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T08:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T09:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T10:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T11:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T12:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T13:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T14:00:00Z'
Successfully got data from InfluxDB SELECT FIRST(*) FROM "sun_azimuth" where time>'2017-10-03T15:00:00Z'
Traceback (most recent call last):
  File "/etc/openhab2/scripts/shaddow.py", line 247, in <module>
    main()
  File "/etc/openhab2/scripts/shaddow.py", line 241, in main
    s.generateSVG()
  File "/etc/openhab2/scripts/shaddow.py", line 211, in generateSVG
    svg = svg + self.generateArc(WIDTH/2+8,PRIMARY_COLOR,DEGS[i],DEGS[j],'stroke-width="3" fill="none" stroke-opacity="0.2"')	
  File "/etc/openhab2/scripts/shaddow.py", line 74, in generateArc
    angle = end-start
TypeError: unsupported operand type(s) for -: 'NoneType' and 'NoneType'

astro.items:

Number		sun_elevation		"elevation [%.2f °]"		<sun>		    (gAstro)	{ channel="astro:sun:home:position#elevation" }
Number      sun_azimuth         "azimuth"                   <sun>           (gAstro)    { channel="astro:sun:home:position#azimuth" }
Number	    sun_rise_azimuth
Number	    sun_set_azimuth

influxdb.persist:

Strategies {
    everyMinute	: "0 * * * * ?"
    everyHour	: "0 0 * * * ?"
    everyDay	: "0 0 0 * * ?"

    default = everyChange, restoreOnStartup
}

Items {
    sun_azimuth             : strategy = everyHour
}

shaddow.py:

.......    
self.debug = False 
self.oh = openhab()
self.azimuth = float(self.oh.getState('sun_azimuth'))
self.elevation = float(self.oh.getState('sun_elevation'))
self.sr = self.oh.getState('sun_rise_azimuth')
self.ss = self.oh.getState('sun_set_azimuth')
self.sunrise_azimuth = float(self.sr) if self.sr != 'NULL' else 0
self.sunset_azimuth = float(self.ss) if self.ss != 'NULL' else 0
ts = time.time()
utc_offset = (datetime.fromtimestamp(ts) - datetime.utcfromtimestamp(ts)).total_seconds()/3600
for h in xrange(0,24,HOURS):
    t = datetime.combine(date.today(), datetime.min.time()) + timedelta(hours=-utc_offset+h-24)
   	    a = self.oh.getStateHistoryFromInflux('sun_azimuth',t.strftime('%Y-%m-%dT%H:%M:%S') + 'Z')
   	    DEGS.extend([a])
.......

root@srv-openhab:/var/log/openhab2# pip --version
pip 8.1.1 from /usr/lib/python2.7/dist-packages (python 2.7)
root@srv-openhab:/var/log/openhab2# pip3 --version
pip 8.1.1 from /usr/lib/python3/dist-packages (python 3.5)

What else to show, I do not know :slight_smile:
What am I doing wrong?
Thank you!

Sorry for the simple question regarding this:

In HABpanel, what is the widget type for the .svg image? Is it an image-type widget or something else?

Thanks!

I think it was necessary to wait for the first storage in influxdb of the azimuth value. After saving it, there are no errors.
Show an example of output shaddow.svg in the widget habpanel.
Thank you!

To add to HABPanel:

Add a template widget with this content:

<object data="/static/matrix-theme/shaddow.svg?{{itemValue('Sun_Azimuth')}}" type="image/svg+xml"></object>      

The ?{{itemValue(‘Sun_Azimuth’)}} ensures that the SVG gets refreshed automatically as the azimuth changes.

1 Like

Many thanks. I’ll give that a go.

Is this working with rrd4j persitence also? Do i have to change something inside the python script or inside your rule?

Sun_Azimuth is already persisted in my setup for other things.

No, it’s not compatible with other persistence layers. One would have to adapt the script.

It should theoretically be possible to get the same data from OH from any persistence if you replaced your direct query to InfluxDB with calls to OH’s REST based Persistence API.

This would be great if someone can change this. It would make the script more general.

I get exactly the same error and I had it running since yesterday afternoon so I’m not convinced of your solution of just waiting. Can you remember if you did anything else to fix it?

Thanks.

Successfully got data from InfluxDB
Successfully got data from InfluxDB
Successfully got data from InfluxDB
Successfully got data from InfluxDB
Traceback (most recent call last):
  File "/etc/openhab2/scripts/shaddow.py", line 245, in <module>
    main()
  File "/etc/openhab2/scripts/shaddow.py", line 239, in main
    s.generateSVG()
  File "/etc/openhab2/scripts/shaddow.py", line 209, in generateSVG
    svg = svg + self.generateArc(WIDTH/2+8,PRIMARY_COLOR,DEGS[i],DEGS[j],'stroke-width="3" fill="none" stroke-opacity="0.2"')	
  File "/etc/openhab2/scripts/shaddow.py", line 72, in generateArc
    angle = end-start
TypeError: unsupported operand type(s) for -: 'NoneType' and 'NoneType'

Looks like the historical values are not in influxDb. I added some error handling to the files. Please re-download both files and try again.

1 Like

I did that (thank you) and get this error:

2017-10-05 15:16:12.412 [INFO ] [lipse.smarthome.model.script.Shaddow] - Updating Shaddow SVG
2017-10-05 15:16:12.416 [INFO ] [lipse.smarthome.model.script.Shaddow] - Traceback (most recent call last):
  File "/etc/openhab2/scripts/shaddow.py", line 5, in <module>
    from myopenhab import openhab
ImportError: cannot import name openhab

My influx dB name is openhab and I changed the reference to it in your myopenhab script:

payload = {'db': 'openhab', 'q': sql}
1 Like