0

I have a Python function set up to text me if my house gets above 30 degrees Celsius. The script also drives and LCD display that loops through various bits of weather info: house temp, humidity, outdoor conditions, and the times of streetcars.

Because the script is based on a loop, I get a text message every minute or so as long as the temperature is above 30 C. Ideally, I would like to find an elegant way to put the function to sleep while still calling it to check the temperature.

Below is an example of the code I'm using to trigger the IFTTT:

def send_event(api_key, event, value1=None, value2=None, value3=None):
"""Send an event to the IFTTT maker channel"""
url = "https://maker.ifttt.com/trigger/{e}/with/key/{k}/".format(e=event,
                                                                 k=api_key)
payload = {'value1': value1, 'value2': value2, 'value3': value3}
return requests.post(url, data=payload)

Any and all help appreciated.

Thanks!

  • I don't understand what you want. You either want a function to do something or not to do anything. You can't have it do both at the same time, it's an irrational requirement. Please elaborate on exactly what you have and what you need. – freakish Jul 25 '16 at 00:05
  • Coroutines are great for making Python threads sleep. If you're using a recent version of Python you could try async methods as well. – Wolph Jul 25 '16 at 00:19

2 Answers2

0

Instead of trying to stop your loop from continuing, you should record when the last alert was sent and only resend if enough time has elapsed since the last alert.

Whenever a temperature alert gets sent, have it record the datetime to a variable. Each time the function is called, have it compare the current datetime to the variable to see if the difference is greater than a certain threshold. If it is, re-send the alert and replace the last alert veriable with the current datetime.

from datetime import datetime

alert_interval = 1800 # 30 minutes in seconds
last_alert = datetime(1, 1, 1) # set the initial time to very long ago

def send_event():
    time_diff = datetime.now() - last_alert # get a timedelta
    if time_diff.total_seconds() >= alert_interval:
        last_alert = datetime.now()
        # call the API to send another alert
Soviut
  • 88,194
  • 49
  • 192
  • 260
0

If I understand correctly, the problem is that you get too many texts. In that case, store some state about the previous events and use that to decide whether or not to send a text.

For example, a simple boolean (True/False) variable can be used as a simple flag. You can still use a loop, but only send an event on the first time it gets above 30 degrees and reset when it falls below:

temp_is_high = False

while True:
    data = weather.get_data()

    if data['temp'] > 30:
        # only send if we are going from "cool" to "hot"
        # not if we were already in "hot" mode
        if not temp_is_high:
            # we are not in "hot" mode: remember for next time
            temp_is_high = True
            send_event(...)
   else: 
       # reset the condition flag
       temp_is_high = False

There are variation on this theme. For example, you might want to add hysteresis in so that if your thermostat is set to 30 degrees, and the house temperature is hovering around that, measurements of [29, 30, 29, 30, 29, 30, ....] won't send a text every time. To do that, only reset the "hot mode" flag when the temperature, having passed 30, falls below (say) 26 degrees. Or 1 hour has passed, or any number of your own requirements.

Inductiveload
  • 6,094
  • 4
  • 29
  • 55
  • This looks closest to what I was trying to do. Yes, you're right—too many texts. Every time the loop goes round I get a text telling me the house is more than 30 Celsius. This is my first Python project. Can you suggest how I might work in your suggestions to this function: `def home_temp_text_alert(ifttt_api_key, event_1, value1=None, value2=None): home_temp_text_alert_sleep = 0 url = "https://maker.ifttt.com/trigger/{e}/with/key/{k}".format(e=event_1,k=ifttt_api_key) payload = {"value1": value1, "value2": value2} return requests.post(url, data=payload)` – Chris Bateman Jul 25 '16 at 00:56
  • You don't work them into that function, that function is what sends the text, which you don't want to do on each loop. You call `home_temp_text_alert(...)` instead of my placeholder `send_event(...)`. You replace the `data = ...` line with whatever gets you `value1` and `value2`, which I assume is how you get the temperature? – Inductiveload Jul 25 '16 at 07:44
  • Thank you for this! – Chris Bateman Jul 26 '16 at 00:51