Announcement

Collapse
No announcement yet.

Solar Position Script

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Solar Position Script

    Below is a script that will calculate the solar azimuth and altitude (i.e. the position of the sun in the sky) and put the values in two virtual devices. These devices can then be used to determine whether to close blinds/shades, etc. I found the base code on the internet and have been running it here for a couple of days and seems to be relatively accurate (at least for my location). To use it, create two virtual devices (see screenshots below), and edit the script with the reference IDs of those devices and also your local lat/long. I run the script using a recurring event (every 5 minutes, but adjust to whatever you want for an update time). It's only been tested on Windows and may need some minor mods to work on linux.


    Click image for larger version

Name:	Capture.PNG
Views:	1276
Size:	41.4 KB
ID:	1286065
    Click image for larger version

Name:	Capture1.PNG
Views:	1008
Size:	69.0 KB
ID:	1286066
    Click image for larger version

Name:	Capture2.PNG
Views:	988
Size:	57.3 KB
ID:	1286067
    Code:
     'From c code posted here: http://www.psa.es/sdg/sunpos.htm
     'VB.NET Conversion posted here: http://www.vbforums.com/showthread.php?832645-Solar-position-calculator
     'converted for HomeSeer use by Sparkman v1.0
    
    Imports System.Math
    
    Sub Main(ByVal Parms As String)
        Dim Debug As Boolean = False
        Dim logName As String = "Solar Position"
        Dim dLatitude As Double = [B]51.1[/B]
        Dim dLongitude As Double = [B]-115.1[/B]
        Dim hsAzimuthDevice As Integer = [B]1234[/B]
        Dim hsAltitudeDevice As Integer = [B]1235[/B]
    
        Dim pi As Double = 3.14159265358979
        Dim rad As Double = pi / 180
        Dim dEarthMeanRadius As Double = 6371.01
        Dim dAstronomicalUnit As Double = 149597890
    
        Dim iYear As Integer = DateTime.UtcNow.Year
        Dim iMonth As Integer = DateTime.UtcNow.Month
        Dim iDay As Integer = DateTime.UtcNow.Day
        Dim dHours As Double = DateTime.UtcNow.Hour
        Dim dMinutes As Double = DateTime.UtcNow.Minute
        Dim dSeconds As Double = DateTime.UtcNow.Second
    
        Dim dZenithAngle As Double
        Dim dZenithAngleParallax As Double
        Dim dAzimuth As Double
        Dim dAltitudeAngle As Double
        Dim dElapsedJulianDays As Double
        Dim dDecimalHours As Double
        Dim dEclipticLongitude As Double
        Dim dEclipticObliquity As Double
        Dim dRightAscension As Double
        Dim dDeclination As Double
        Dim dY As Double
        Dim dX As Double
        Dim dJulianDate As Double
        Dim liAux1 As Integer
        Dim liAux2 As Integer
        Dim dMeanLongitude As Double
        Dim dMeanAnomaly As Double
        Dim dOmega As Double
        Dim dSin_EclipticLongitude As Double
        Dim dGreenwichMeanSiderealTime As Double
        Dim dLocalMeanSiderealTime As Double
        Dim dLatitudeInRadians As Double
        Dim dHourAngle As Double
        Dim dCos_Latitude As Double
        Dim dSin_Latitude As Double
        Dim dCos_HourAngle As Double
        Dim dParallax As Double
    
        Try
    
            ' Calculate difference in days between the current Julian Day and JD 2451545.0, which is noon 1 January 2000 Universal Time
            ' Calculate time of the day in UT decimal hours
            dDecimalHours = dHours + (dMinutes + dSeconds / 60.0) / 60.0
            ' Calculate current Julian Day
            liAux1 = (iMonth - 14) \ 12
            liAux2 = (1461 * (iYear + 4800 + liAux1)) \ 4 + (367 * (iMonth - 2 - 12 * liAux1)) \ 12 - (3 * ((iYear + 4900 + liAux1) \ 100)) \ 4 + iDay - 32075
            dJulianDate = CDbl(liAux2) - 0.5 + dDecimalHours / 24.0
            ' Calculate difference between current Julian Day and JD 2451545.0
            dElapsedJulianDays = dJulianDate - 2451545.0
            If Debug Then hs.writelog(logName,"Elapsed Julian Days Since 2000/01/01: " & CStr(dElapsedJulianDays))
    
            ' Calculate ecliptic coordinates (ecliptic longitude and obliquity of the ecliptic in radians but without limiting the angle to be less than 2*Pi
            ' (i.e., the result may be greater than 2*Pi)
            dOmega = 2.1429 - 0.0010394594 * dElapsedJulianDays
            dMeanLongitude = 4.895063 + 0.017202791698 * dElapsedJulianDays ' Radians
            dMeanAnomaly = 6.24006 + 0.0172019699 * dElapsedJulianDays
            dEclipticLongitude = dMeanLongitude + 0.03341607 * Math.Sin(dMeanAnomaly) + 0.00034894 * Math.Sin(2 * dMeanAnomaly) - 0.0001134 - 0.0000203 * Math.Sin(dOmega)
            dEclipticObliquity = 0.4090928 - 0.000000006214 * dElapsedJulianDays + 0.0000396 * Math.Cos(dOmega)
            If Debug Then hs.writelog(logName,"Ecliptic Longitude: " & CStr(dEclipticLongitude))
            If Debug Then hs.writelog(logName,"Ecliptic Obliquity: " & CStr(dEclipticObliquity))
    
            ' Calculate celestial coordinates ( right ascension and declination ) in radians but without limiting the angle to be less than 2*Pi (i.e., the result may be greater than 2*Pi)
            dSin_EclipticLongitude = Math.Sin(dEclipticLongitude)
            dY = Math.Cos(dEclipticObliquity) * dSin_EclipticLongitude
            dX = Math.Cos(dEclipticLongitude)
            dRightAscension = Math.Atan2(dY, dX)
            If dRightAscension < 0.0 Then
                dRightAscension = dRightAscension + (2 * pi)
            End If
            dDeclination = Math.Asin(Math.Sin(dEclipticObliquity) * dSin_EclipticLongitude)
            If Debug Then hs.writelog(logName,"Declination: " & CStr(dDeclination))
    
            ' Calculate local coordinates ( azimuth and zenith angle ) in degrees
            dGreenwichMeanSiderealTime = 6.6974243242 + 0.0657098283 * dElapsedJulianDays + dDecimalHours
            dLocalMeanSiderealTime = (dGreenwichMeanSiderealTime * 15 + dLongitude) * rad
            dHourAngle = dLocalMeanSiderealTime - dRightAscension
            If Debug Then hs.writelog(logName,"Hour Angle: " & CStr(dHourAngle))
            dLatitudeInRadians = dLatitude * rad
            dCos_Latitude = Math.Cos(dLatitudeInRadians)
            dSin_Latitude = Math.Sin(dLatitudeInRadians)
            dCos_HourAngle = Math.Cos(dHourAngle)
            dZenithAngle = (Math.Acos(dCos_Latitude * dCos_HourAngle * Math.Cos(dDeclination) + Math.Sin(dDeclination) * dSin_Latitude))
            dY = -Math.Sin(dHourAngle)
            dX = Math.Tan(dDeclination) * dCos_Latitude - dSin_Latitude * dCos_HourAngle
            dAzimuth = Math.Atan2(dY, dX)
            If dAzimuth < 0.0 Then
                dAzimuth = dAzimuth + (2 * pi)
            End If
            dAzimuth = dAzimuth / rad
    
            If Debug Then hs.writelog(logName,"Azimuth: " & CStr(dAzimuth))
            hs.setdevicevaluebyref(hsAzimuthDevice,dAzimuth,True)
    
            ' Parallax Correction
            dParallax = (dEarthMeanRadius / dAstronomicalUnit) * Math.Sin(dZenithAngle)
            dZenithAngleParallax = (dZenithAngle + dParallax) / rad
            dAltitudeAngle = (dZenithAngleParallax * -1) + 90
    
            If Debug Then hs.writelog(logName,"Altitude Angle: " & CStr(dAltitudeAngle))
            hs.setdevicevaluebyref(hsAltitudeDevice,dAltitudeAngle,True)
    
        Catch ex As Exception
            hs.WriteLog(logName, "Exception " & ex.ToString)
        End Try
    
    End Sub
    HS 4.2.8.0: 2134 Devices 1252 Events
    Z-Wave 3.0.10.0: 133 Nodes on one Z-Net

    #2
    Al... this is great. Thanks. I'm looking at this as my next automation project so I can close off the blinds to save my baby grand from the impending heat... Can elaborate what you're using for blind control?

    Thanks,

    Robert
    HS3PRO 3.0.0.500 as a Fire Daemon service, Windows 2016 Server Std Intel Core i5 PC HTPC Slim SFF 4GB, 120GB SSD drive, WLG800, RFXCom, TI103,NetCam, UltraNetcam3, BLBackup, CurrentCost 3P Rain8Net, MCsSprinker, HSTouch, Ademco Security plugin/AD2USB, JowiHue, various Oregon Scientific temp/humidity sensors, Z-Net, Zsmoke, Aeron Labs micro switches, Amazon Echo Dots, WS+, WD+ ... on and on.

    Comment


      #3
      Originally posted by langenet View Post
      Al... this is great. Thanks. I'm looking at this as my next automation project so I can close off the blinds to save my baby grand from the impending heat... Can elaborate what you're using for blind control?

      Thanks,

      Robert
      Hi Robert, I'm using Bali cellular shades with AutoView motors/controls. They are Z-Wave based. Bali Blinds can be bought through Costco, Home Depot, Lowe's and blinds.ca.

      Cheers
      Al
      HS 4.2.8.0: 2134 Devices 1252 Events
      Z-Wave 3.0.10.0: 133 Nodes on one Z-Net

      Comment


        #4
        Al, I implemented you script - thank you. But how are you verifying the data? Doing the math or is there a site you're verifying against?
        HS3PRO 3.0.0.500 as a Fire Daemon service, Windows 2016 Server Std Intel Core i5 PC HTPC Slim SFF 4GB, 120GB SSD drive, WLG800, RFXCom, TI103,NetCam, UltraNetcam3, BLBackup, CurrentCost 3P Rain8Net, MCsSprinker, HSTouch, Ademco Security plugin/AD2USB, JowiHue, various Oregon Scientific temp/humidity sensors, Z-Net, Zsmoke, Aeron Labs micro switches, Amazon Echo Dots, WS+, WD+ ... on and on.

        Comment


          #5
          Originally posted by langenet View Post
          Al, I implemented you script - thank you. But how are you verifying the data? Doing the math or is there a site you're verifying against?
          I found a few sites I verified it with and also the sunset/sunrise times it calculates are very close to what HS has for sunset/sunrise times. When the azimuth value becomes a negative number, it is sunset and when it becomes positive, it is sunrise.
          HS 4.2.8.0: 2134 Devices 1252 Events
          Z-Wave 3.0.10.0: 133 Nodes on one Z-Net

          Comment


            #6
            Can you share a link Al? I'm using https://planetcalc.com/4270/ but the numbers don't jive...
            HS3PRO 3.0.0.500 as a Fire Daemon service, Windows 2016 Server Std Intel Core i5 PC HTPC Slim SFF 4GB, 120GB SSD drive, WLG800, RFXCom, TI103,NetCam, UltraNetcam3, BLBackup, CurrentCost 3P Rain8Net, MCsSprinker, HSTouch, Ademco Security plugin/AD2USB, JowiHue, various Oregon Scientific temp/humidity sensors, Z-Net, Zsmoke, Aeron Labs micro switches, Amazon Echo Dots, WS+, WD+ ... on and on.

            Comment


              #7
              Originally posted by langenet View Post
              Can you share a link Al? I'm using https://planetcalc.com/4270/ but the numbers don't jive...
              This is one of the ones I tried: https://planetcalc.com/320/

              Right now, it shows Azimuth 173.27 and altitude 27.19. My virtual devices show 173.8 and 27.5, so close enough for my purposes. How far is yours off? Likely a timezone adjustment issue.
              HS 4.2.8.0: 2134 Devices 1252 Events
              Z-Wave 3.0.10.0: 133 Nodes on one Z-Net

              Comment


                #8
                Right now the site shows 233.67 and altitude of 16.13. My virtual devices show 220 and 24.5. My Latitude is 45.42 an my long is 75.67.

                HS3PRO 3.0.0.500 as a Fire Daemon service, Windows 2016 Server Std Intel Core i5 PC HTPC Slim SFF 4GB, 120GB SSD drive, WLG800, RFXCom, TI103,NetCam, UltraNetcam3, BLBackup, CurrentCost 3P Rain8Net, MCsSprinker, HSTouch, Ademco Security plugin/AD2USB, JowiHue, various Oregon Scientific temp/humidity sensors, Z-Net, Zsmoke, Aeron Labs micro switches, Amazon Echo Dots, WS+, WD+ ... on and on.

                Comment


                  #9
                  langenet What are you using as the Time Zone value on that web page and where do you think the sun is approx. in real life?
                  HS 4.2.8.0: 2134 Devices 1252 Events
                  Z-Wave 3.0.10.0: 133 Nodes on one Z-Net

                  Comment


                    #10
                    That's embarrassing... Yes, I had to change the time zone to 5 .. So the numbers now line up and my virtual devices show 224.7 and 22.2. while the site shows 224.5 and 21.68. Close enough for the government!

                    Great work. Thanks for all your help!

                    Robert
                    HS3PRO 3.0.0.500 as a Fire Daemon service, Windows 2016 Server Std Intel Core i5 PC HTPC Slim SFF 4GB, 120GB SSD drive, WLG800, RFXCom, TI103,NetCam, UltraNetcam3, BLBackup, CurrentCost 3P Rain8Net, MCsSprinker, HSTouch, Ademco Security plugin/AD2USB, JowiHue, various Oregon Scientific temp/humidity sensors, Z-Net, Zsmoke, Aeron Labs micro switches, Amazon Echo Dots, WS+, WD+ ... on and on.

                    Comment


                      #11
                      Originally posted by langenet View Post
                      That's embarrassing... Yes, I had to change the time zone to 5 .. So the numbers now line up and my virtual devices show 224.7 and 22.2. while the site shows 224.5 and 21.68. Close enough for the government!

                      Great work. Thanks for all your help!

                      Robert
                      You're welcome and glad it's working for you!

                      Cheers
                      Al
                      HS 4.2.8.0: 2134 Devices 1252 Events
                      Z-Wave 3.0.10.0: 133 Nodes on one Z-Net

                      Comment


                        #12
                        Originally posted by sparkman

                        Yes, these numbers by themselves are somewhat meaningless. I use these numbers along with other factors such as light levels to determine whether to open or close shades.
                        How are you doing it?


                        Might be interesting to have a comprehensive script (like the zwave lock script) with a single screen defining possible variables for each 'space'...
                        in-room LUX
                        window/door facing (compass direction)
                        outside shading factor (trees, overhangs, etc)
                        inside shading factor (type of window coverings)
                        etc
                        ... using those with the solar position to calculate when it is light or dark in each 'space'.

                        or maybe I just use LUX.

                        Comment


                          #13
                          Originally posted by Ltek View Post

                          How are you doing it?
                          Light levels (ie. how bright it is outside) and in one room, whether the TV is on and whether the room is occupied. I also plan to factor outside temperature and potentially the forecast high termperature to see if shades on the south side of the house should be closed. In the winter, I want them open as much as possible to get the heat from the sun, unless the low sun shines on the tv or in people's eyes that are sitting in the room. I only have a few blinds automated at this point and it's unlikely I'll do more soon, so I don't plan to develop a general purpose script/web page/plugin for it. It's kind of trial and error to determine the azimuth range, elevation and brightness of the sun for which to lower the shades and by how much. Here's a script that I run for one room which uses a multiplier with the azimuth to determine the position (0 is fully closed for my blinds and 99 is fully open).

                          Code:
                          Sub Main(ByVal Parms as String)
                          
                              dim Debug as Boolean = False
                              Dim logName As String = "Solar Shade"                    'set log name for HS log
                          
                              Dim ParmArray() as String
                              ParmArray = Parms.tostring.split(",")
                              dim devSolarAltitude as Double = CDbl(ParmArray(0))        'reference ID of the device to use for Solar Altitude
                              dim devShadePosition as Double = CDbl(ParmArray(1))        'reference ID of the shade/blind device
                              dim Multiplier as Double = CDbl(ParmArray(2))            'value for adjusting the altitude to determine the shade position
                          
                              Dim SolarAltitude As Double
                              Dim CurrentShadePosition,NewShadePosition As Integer
                              SolarAltitude = hs.DeviceValueEx(devSolarAltitude)
                              CurrentShadePosition = hs.DeviceValue(devShadePosition)
                          
                              If Debug Then hs.writelog(logName,CStr(devSolarAltitude) & ":" & CStr(SolarAltitude))
                          
                              NewShadePosition = CInt(SolarAltitude * Multiplier)
                              If Math.Abs(NewShadePosition - CurrentShadePosition) > 4 Then 'only adjust the shades if change is more than 4%
                                  Select Case NewShadePosition
                                      Case 1 to 98
                                          ' Device DIM, set its current dim level
                                          hs.CAPIControlHandler(hs.CAPIGetSingleControl(devShadePosition, false, CStr(NewShadePosition), false, true))
                                          If Debug Then hs.writelog(logName,CStr(devShadePosition) & ":" & CStr(NewShadePosition))
                                      Case > 98
                                          ' Device ON, set it to on
                                          hs.CAPIControlHandler(hs.CAPIGetSingleControl(devShadePosition, false, "On", false, false))
                                          If Debug Then hs.writelog(logName,CStr(devShadePosition) & " Set to On")
                                      Case < 1
                                          ' Device OFF, set it to off
                                          hs.CAPIControlHandler(hs.CAPIGetSingleControl(devShadePosition, false, "Off", false, true))
                                          If Debug Then hs.writelog(logName,CStr(devShadePosition) & " Set to Off")
                                  End Select
                              Else
                                  If Debug Then hs.writelog(logName,"Blinds Not Adjusted as only different by " & Math.Abs(NewShadePosition - CurrentShadePosition) & "%")
                              End If
                          
                          End Sub
                          HS 4.2.8.0: 2134 Devices 1252 Events
                          Z-Wave 3.0.10.0: 133 Nodes on one Z-Net

                          Comment


                            #14
                            Originally posted by sparkman View Post
                            Below is a script that will calculate the solar azimuth and altitude (i.e. the position of the sun in the sky) and put the values in two virtual devices. ...
                            This works great! Thanks for posting it. Now, I have to figure out how to use it to close my motorized blinds. Elliott
                            "Living with technology means living in a [constant] state of flux." S. Higgenbotham, 2023
                            "Reboot and rejoice!" F. Pishotta, 1989

                            Comment


                              #15
                              Originally posted by sparkman View Post

                              Light levels (ie. how bright it is outside) and in one room, whether the TV is on and whether the room is occupied. I also plan to factor outside temperature and potentially the forecast high termperature to see if shades on the south side of the house should be closed. In the winter, I want them open as much as possible to get the heat from the sun, unless the low sun shines on the tv or in people's eyes that are sitting in the room. I only have a few blinds automated at this point and it's unlikely I'll do more soon, so I don't plan to develop a general purpose script/web page/plugin for it. It's kind of trial and error to determine the azimuth range, elevation and brightness of the sun for which to lower the shades and by how much. Here's a script that I run for one room which uses a multiplier with the azimuth to determine the position (0 is fully closed for my blinds and 99 is fully open).

                              Code:
                              Sub Main(ByVal Parms as String)
                              
                              dim Debug as Boolean = False
                              Dim logName As String = "Solar Shade" 'set log name for HS log
                              
                              Dim ParmArray() as String
                              ParmArray = Parms.tostring.split(",")
                              dim devSolarAltitude as Double = CDbl(ParmArray(0)) 'reference ID of the device to use for Solar Altitude
                              dim devShadePosition as Double = CDbl(ParmArray(1)) 'reference ID of the shade/blind device
                              dim Multiplier as Double = CDbl(ParmArray(2)) 'value for adjusting the altitude to determine the shade position
                              
                              Dim SolarAltitude As Double
                              Dim CurrentShadePosition,NewShadePosition As Integer
                              SolarAltitude = hs.DeviceValueEx(devSolarAltitude)
                              CurrentShadePosition = hs.DeviceValue(devShadePosition)
                              
                              If Debug Then hs.writelog(logName,CStr(devSolarAltitude) & ":" & CStr(SolarAltitude))
                              
                              NewShadePosition = CInt(SolarAltitude * Multiplier)
                              If Math.Abs(NewShadePosition - CurrentShadePosition) > 4 Then 'only adjust the shades if change is more than 4%
                              Select Case NewShadePosition
                              Case 1 to 98
                              ' Device DIM, set its current dim level
                              hs.CAPIControlHandler(hs.CAPIGetSingleControl(devShadePosition, false, CStr(NewShadePosition), false, true))
                              If Debug Then hs.writelog(logName,CStr(devShadePosition) & ":" & CStr(NewShadePosition))
                              Case > 98
                              ' Device ON, set it to on
                              hs.CAPIControlHandler(hs.CAPIGetSingleControl(devShadePosition, false, "On", false, false))
                              If Debug Then hs.writelog(logName,CStr(devShadePosition) & " Set to On")
                              Case < 1
                              ' Device OFF, set it to off
                              hs.CAPIControlHandler(hs.CAPIGetSingleControl(devShadePosition, false, "Off", false, true))
                              If Debug Then hs.writelog(logName,CStr(devShadePosition) & " Set to Off")
                              End Select
                              Else
                              If Debug Then hs.writelog(logName,"Blinds Not Adjusted as only different by " & Math.Abs(NewShadePosition - CurrentShadePosition) & "%")
                              End If
                              
                              End Sub
                              Al this is very interesting. So you call this via an event and pass in the three parameters? How often is this run? How is the multiplier parameter determined? Hit/miss.
                              I will be purchasing some Bali blinds very soon so I'm keenly interested in implementing this.. Would you mind showing your event?

                              As well, do you use Alexa and do you know if you can tell Alexa to open/close the blinds natively. I suppose using Jon's helper that's possible but wasn't sure if Alexa supports this.

                              Thanks,

                              Robert
                              HS3PRO 3.0.0.500 as a Fire Daemon service, Windows 2016 Server Std Intel Core i5 PC HTPC Slim SFF 4GB, 120GB SSD drive, WLG800, RFXCom, TI103,NetCam, UltraNetcam3, BLBackup, CurrentCost 3P Rain8Net, MCsSprinker, HSTouch, Ademco Security plugin/AD2USB, JowiHue, various Oregon Scientific temp/humidity sensors, Z-Net, Zsmoke, Aeron Labs micro switches, Amazon Echo Dots, WS+, WD+ ... on and on.

                              Comment

                              Working...
                              X