Crashed the party

Last night this statement crashed before midnight because of a new year come up. NextDay was 1 and Val(Hr_Off_Time_ComboBox.value) was 2 and Val(Min_Off_Time_ComboBox.value)) was 30. The device was to turn of at 2:30am. I was thinking the datetime would increment to 2021. This statement is triggered once at dusk.
Anyone have a better approach?

OffTimevalue = New DateTime(datetime.now.year,datetime.now.month, datetime.now.day + NextDay, Val(Hr_Off_Time_ComboBox.value),Val(Min_Off_Time_ComboBox.value))

use or try
date = datenow + new DateInterval(…

2 Likes

The DateInterval is the way to do it. I was doing similar to the OP in a routine and then I noticed that the way I was incrementing my dates, I could end up with things like 31 November or 32nd December! Properly using a DateInterval fixed that bug!

That’s not a bug but a user error :wink:

1 Like

This becomes confusing to me in that the trigger to turn on my smart switch is determined by an ambient light level. I do not know exactly what time that will be. I want to be able to turn that device off at some hour after midnight determined buy my selected time values Val(Hr_Off_Time_ComboBox.value)
and Val(Min_Off_Time_ComboBox.value). Somehow I need to set a turn off DateTime to the next day if my selected time is past midnight.

It’s simple. You basically create a date when the switch turns on. Then you get the of the week from that date.

Now create a new date where the day of the week is incremented by 1 and add in the desired off time.

I was just looking in my code to give an example and noticed I had not fixed all of the bugs in all of the places where I thought I had! So sorry - no example until I fix it. I give my users the options to schedule things:

daily
weekly
monthly
yearly
specific days
every nth day of the week (every 3rd Monday of the month lets say)

It’s a lot of date and date interval juggling.

if this light go on today 2.1.2021 23:00
New DateTime(datetime.now.year, datetime.now.month, datetime.now.day,0,0,0) = 2.1.2021 00:00
add new DateInterval(0,0,1) for next day = 3.1.2021 00:00
add new DateInterval(0,0,0, hour = 2, minute = 15) = 3.1.2021 02:15

1 Like

So here’s how you would do it.

When the light turns on:

Dim di as New DateInterval(0,0,1)
Dim d as DateTime = DateTime.Now+di

Now d is a Date that is 24 hours after the light turned on but there’s a method to my madness:

Dim DateOff as New DateTime(d.Year,d.Month,D.Day,DesiredHour,DesiredMinute,DesiredSecond)

Where DesiredHour, DesiredMinute,DesiredSecond are your off time.

Now calculate the period for your timer that will execute your turnoff code:

Dim TimerOffMilliseconds as Double = (DateOff.SecondsFrom1970-DateTime.Now.Secondsfrom1970)*1000
OffTimer.Period = TimerOffMilliseconds
OffTimer.Enabled = True

Or alternatively, if you have a method called TurnSwitchOff you could do:

Timer.CallLater(TimerOffMilliseconds, AddressOf TurnSwitchOff)

That should do it.

1 Like

I didn’t think about creating a date based on the current day but at midnight. Then adding the day and time interval is a good way to do it. I think you could do it all in one:

Dim d as New DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day,0,0,0)
Dim di as New DateInterval(0,0,1,2,15)
d = d+di
Dim TimerOffMilliseconds as Double = (d.SecondsFrom1970-DateTime.Now.SecondsFrom1970)*1000

Timer.CallLater(TimerOffMilliseconds,AddressOf TurnSwitchOff)

Makes it a little cleaner than my code…

I believe I understand your technique but the timer in my case would be unnecessary since my code contentiously cycles ever 15 seconds and checks to see if the turn off time has been reached. But the timer is another good approach and maybe better. I have about 20+ of these devices being monitored continuously.

Why cycle your code. The timer is a built in function to do this. I do a similar thing. I have a MasterTimer that runs every 24 hours. I have all my devices that are automated in a Dictionary. The master timer looks at all of the devices. If their “action” time is within 24 hours then it starts a timer for each device (the timer is a proper of the device). For device who need to do something more than 24 hours out, it just let’s them be. This way you only have timers running for what you need done today.

Having a timer set up is far more efficient than a cycle in your code to check every 15 seconds when 99% of the time, nothing is going to happen. Set the time for when you need to turn your device off and leave it be.

if you compare the dates each 15 seconds you could also show the remaining time if this is a gui app.

I think you are right, Jon. In this home automation program, many sensors (motion, light, temperature) and inputs > 50 are continuously monitored and if not in real-time I might miss events or have a lag time for response. I wish I had a way to create interrupts. These new smart switches > 20 just got added into the mix. If I was rewriting I could use more timers but it could be a real chore deciding at what frequency I wanted to check each. I know that may sound a bit lazy and you’re probably right.

Mine is somewhat of a home automation product as well but more related to automating things like A/V systems although I can automate just about anything that is addressable over the network. I’m not so interested in monitoring specific values of things like you are though. I just want them to do things at specific times really.

So instead of interrupts think events. How are you monitoring your devices? Via TCP/IP? RS-232? Are the devices periodically reporting or do you have to poll them? If you have to poll them, then I agree, you need to do that on a repeating basis. I do actually have devices in my app (the main function of it) that I continuously monitor. So yeah, I get it. But if the devices periodically wake up and send you data, then you will get an event raised when that data comes in. That’s the idea thing. In most wireless home automation devices today using things like WiFi or Bluetooth, the devices are asleep most of the time. They periodically wake and send data back on their status. For example I have a FLO system in my house. My FLO water sensors would run out of battery very quickly if the FLO software was polling them every 15 seconds. Rather, they report back to the software (the cloud) every so often. The rest of the time, they are sleeping. So I’d be surprised if you have to poll your devices.

But you can do a mix of the timers, etc. There’s no reason you can’t. Make whatever you do when polling your devices as short and quick as possible. Put the rest that you “schedule” into timers.

That’s interesting and I agree with a mix, especially with these Smart Shelly devices that I am controlling with HTTP commands and of course Google. As you know home automation is a deep pit but very entertaining if you like that kind of thing, I do. My home automation program was designed many years ago when home automation was just a thought and I owned a Commodore 64. I spent 9 years designing and building a home around a hand-built control system incorporating a WIZ232 controller. Dated now but it still pumps away 24/7. The objective was to take passive elements and a hydronic hot water floor heating system and see how efficiently I could heat a home. Interesting algorithms monitor outside environmental elements that help me manage radiant gain such as light intensity, temp, wind, and send energy where needed in the home. Utilizing passive gain with mass storage and air circulating systems are the heart of my system but then it extends to everything from pressurized skylights to eliminate condensation, circulating DHW, dehumidification, air filtration, security, irrigation, and landscape lighting. It paid off with < $40 heat bills per month for the first 15 years. Respectable for a 2700sq ft home started in 1983 in the Pacific North West. One of the issues with the Wiz-232 controller and timers is that the controller only wants to hear one thing at a time and respond in its own sweet time hence a sequential approach. Timers, firing off and looking for controller time whenever can create chaos. This rewrite was to move from an Apple G3 serial interface Wallstreet to a USB interface. Good project during COVID, but almost a total rewrite. Thanks for sharing what you’re up to. Starting over with what is available today for home automation would be a great adventure. Does your FLO system incorporate a mains shutoff?

I guess I’ll see if this work. This is run within a 15 sec timer so the GUI is continuously updated to reflect any change in the status of the devices from an outside Google voice command.

  
  If OnAtDusk.value And Not Device_Trip_Set Then   //  Dark out and On At Dusk checkbox is checked and Trip Time for Device has not been set.
    
    Var OffTimeValueInterval As New DateInterval(0,0,0)
    
    If NextDay = 1 Then // Checkbox
      OffTimeValueInterval = New DateInterval(0,0,1,Val(Hr_Off_Time_ComboBox.value),Val(Min_Off_Time_ComboBox.value))
    Else
      OffTimeValueInterval = New DateInterval(0,0,0,Val(Hr_Off_Time_ComboBox.value),Val(Min_Off_Time_ComboBox.value))
    End
    
    OffTimevalue = New DateTime(datetime.now.year,datetime.now.month, datetime.now.day) + OffTimeValueInterval
    
    Device_Trip_Set = True // Stops time from being set again until LL_Darkout goes false
  End
  
If DateTime.now < OffTimeValue Then// Time less then shutoff time
    S_OnButton.value = True
  Else 
    S_OffButton.value = True
  End
  
Else
  Device_Trip_Set = False // No longer dark, reset
End

I have an extension method that returns the DateTime as 12am.

Public Function ZeroHour(Extends Value As DateTime) as DateTime
  Var Result As DateTime = Value.SubtractInterval(0, 0, 0, Value.Hour, Value.Minute, Value.Second, Value.Nanosecond)
  
  Return Result
End Function

Using this method you can calculate your off time with
Var offTime As DateTime = DateTime.Now.ZeroHour.AddInterval(0, 0, 1, 2, 30)

Assuming you want to turn off tomorrow at 2:30am

1 Like

I’m missing something: Is the Parameter, Extends Value As DateTime?
I don’t seem to find the method ZeroHour when I call it with:
Var offTime As DateTime = DateTime.Now.ZeroHour.AddInterval(0, 0, 1, 2, 30)

I am trying to send this from an action event of a push button:

Var offTime As DateTime = DateTime.Now.ZeroHour.AddInterval(0, 0, 1, 2, 30)
TextField.value = offtime.SQLDateTime

Hi Cliff,

Copy the extension method to a module (mine is called datetimeextensions). Once you’ve done that the method ZeroHour is just another method available when using the datetime object.

Extension methods are awesome :slight_smile:

So these need to be in modules. It did work but I have not used anything like Extends Value As DateTime. Where do you find information about; Extends Value? I’m not sure what it means.