-
Notifications
You must be signed in to change notification settings - Fork 73
Rachio update #421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rjison
wants to merge
2
commits into
tronbyt:main
Choose a base branch
from
rjison:RachioUpdate
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Rachio update #421
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -20,7 +20,6 @@ RACHIO_SECONDARY_COLOR = "#00A676" | |||||
| ACCURACY_IN_MINUTES = 3 #We'll round to the nearest 3 minutes when calling Rachio API | ||||||
| LONG_TTL_SECONDS = 7200 | ||||||
| RACHIO_URL = "https://api.rach.io/1/public" | ||||||
| SAMPLE_DATA = [{"type": "WEATHER_INTELLIGENCE_CLIMATE_SKIP", "date": "Thursday 04:31AM", "summary": "Water all zones was scheduled for 10/03 at 04:26 AM (EDT), but will be skipped based on weather and soil conditions."}, {"type": "WEATHER_INTELLIGENCE_SKIP", "date": "Sunday 04:31AM", "summary": "Water all zones was scheduled for 10/06 at 04:28 AM (EDT), but was skipped due to PLUS weather network which observed 0.00 in and predicted 0.16 in precipitation compared to schedules's threshold of 0.13 in."}, {"type": "SCHEDULE_STARTED", "date": "Tuesday 01:45PM", "summary": "Button press started Quick Run will run for 3 minutes."}, {"type": "SCHEDULE_STARTED", "date": "Tuesday 01:48PM", "summary": "Button press started Quick Run will run for 3 minutes."}, {"type": "SCHEDULE_STARTED", "date": "Tuesday 01:50PM", "summary": "Button press started Quick Run will run for 3 minutes."}, {"type": "SCHEDULE_STARTED", "date": "Tuesday 01:51PM", "summary": "Button press started Quick Run will run for 3 minutes."}, {"type": "SCHEDULE_STARTED", "date": "Tuesday 01:55PM", "summary": "Button press started Quick Run will run for 3 minutes."}, {"type": "WEATHER_INTELLIGENCE_SKIP", "date": "Thursday 04:31AM", "summary": "Water all zones was scheduled for 10/10 at 04:30 AM (EDT), but was skipped due to PLUS weather network which observed 5.10 in and predicted 3.96 in precipitation compared to schedules's threshold of 0.13 in."}, {"type": "WEATHER_INTELLIGENCE_CLIMATE_SKIP", "date": "Sunday 04:36AM", "summary": "Water all zones was scheduled for 10/13 at 04:32 AM (EDT), but will be skipped based on weather and soil conditions."}, {"type": "WEATHER_INTELLIGENCE_CLIMATE_SKIP", "date": "Thursday 04:36AM", "summary": "Water all zones was scheduled for 10/17 at 04:34 AM (EDT), but will be skipped based on weather and soil conditions."}, {"type": "SCHEDULE_STARTED", "date": "Saturday 06:11PM", "summary": "Quick Run will run for 1 minutes."}] | ||||||
| SHORT_TTL_SECONDS = 600 | ||||||
|
|
||||||
| SCHED_START = "SCHEDULE_STARTED" | ||||||
|
|
@@ -50,28 +49,34 @@ def main(config): | |||||
| font_width = 8 | ||||||
|
|
||||||
| if (api_key.strip() == ""): | ||||||
| return display_error_screen(now, "Please enter your API Key", "It can be found in the Rachio App", delay, screen_width, font_height, font) | ||||||
| return display_error_screen(now, "Please enter your API Key", "It can be found in the Rachio App", delay, screen_width, font_height, font, font_width) | ||||||
|
|
||||||
| devices = get_devices(api_key) | ||||||
| selected_device = config.str("device") | ||||||
|
|
||||||
| if (devices == None or selected_device == None or selected_device == ""): | ||||||
| if devices == None: | ||||||
| if (not devices or selected_device == None or selected_device == ""): | ||||||
| if not devices: | ||||||
| # No device selected, and no device available from the list, send an error | ||||||
| return display_error_screen(now, "No devices found.", "Make sure you have entered the correct API key and selected your display device", delay, screen_width, font_height, font, font_width, icon_width) | ||||||
| return display_error_screen(now, "No devices found.", "Check API key and device selection", delay, screen_width, font_height, font, font_width, icon_width) | ||||||
| else: | ||||||
| selected_device = devices[0]["id"] | ||||||
|
|
||||||
| # we have a selected device; otherwise, they've already been sent to the display_error_screen | ||||||
|
|
||||||
| now = time.now().in_location(tz) | ||||||
|
|
||||||
| # If we use the time to the millisecond, nothing will ever be cached and we'll hit our limit of rachio requests in a day | ||||||
| # So we'll round off to the nearest X minutes (They provide enough calls to give you 1 per minutes.) | ||||||
| # But in addition, let's go a few minutes into the future, no point in every making a call that could miss the most recent event. | ||||||
| now = time.now() + time.parse_duration("{}m".format(str(ACCURACY_IN_MINUTES))) | ||||||
|
|
||||||
| rounded_time = time.time(year = now.year, month = now.month, day = now.day, hour = now.hour, minute = round_to_nearest_X(now.minute, ACCURACY_IN_MINUTES), second = 0, location = tz) | ||||||
| # But in addition, let's go a few minutes into the future, no point in ever making a call that could miss the most recent event. | ||||||
|
|
||||||
| # Use the 'now' variable already defined at line 52 | ||||||
| api_time = now + time.parse_duration("{}m".format(ACCURACY_IN_MINUTES)) | ||||||
|
|
||||||
| rounded_time = time.time( | ||||||
| year = api_time.year, | ||||||
| month = api_time.month, | ||||||
| day = api_time.day, | ||||||
| hour = api_time.hour, | ||||||
| minute = round_to_nearest_X(api_time.minute, ACCURACY_IN_MINUTES), | ||||||
| second = 0, | ||||||
| location = tz, | ||||||
| ) | ||||||
|
|
||||||
| # The data they send is a little odd in that the there isn't a time stamp, but a time display. | ||||||
| # So to get the 'last' and 'next' event, you could get all the data at once, and parse through their time display | ||||||
|
|
@@ -143,53 +148,43 @@ def display_error_screen(time, line_3, line_4 = "", delay = 45, screen_width = 6 | |||||
| def render_rachio(tz, config, device_name, recent_events, current_events, now, delay, skip_when_empty = True, screen_width = 64, icon_width = 16, font_height = 8, font_width = 5, font = "5x8"): | ||||||
| show_device_name = config.bool("title_display", True) | ||||||
|
|
||||||
| line_1 = "Rachio" | ||||||
| line_2 = now.format("Mon Jan 2") | ||||||
| line_3 = "" | ||||||
| line_4 = "" | ||||||
|
|
||||||
| if (show_device_name): | ||||||
| line_1 = device_name | ||||||
|
|
||||||
| # 1. Check if we even have events | ||||||
| show_recent_events = recent_events != None and len(recent_events) > 0 | ||||||
|
|
||||||
| if (not show_recent_events): | ||||||
| if not show_recent_events: | ||||||
| if skip_when_empty: | ||||||
| return [] | ||||||
| else: | ||||||
| return display_error_screen(now, "No Events within a week.", "", delay, screen_width, font_height, font, font_width, icon_width) | ||||||
| return display_error_screen(now, "No Events within a week.", "", delay, screen_width, font_height, font, font_width, icon_width) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function
Suggested change
|
||||||
|
|
||||||
| # whew, made it with at least one event to display | ||||||
| # 2. Get our main event data | ||||||
| latest_event = recent_events[len(recent_events) - 1] | ||||||
| readable_date = time.from_timestamp(int(int(latest_event["eventDate"]) / 1000.0)).in_location(tz) | ||||||
|
|
||||||
| #do we have any current events? | ||||||
| show_current_events = current_events != None and len(current_events) > 0 | ||||||
| # 3. Handle the "Stale" logic (Stop showing 'Current' if it's been > 3 hours) | ||||||
| time_since_event = now - readable_date | ||||||
| is_stale = time_since_event > time.parse_duration("3h") | ||||||
|
|
||||||
| if show_recent_events: | ||||||
| latest_event = recent_events[len(recent_events) - 1] | ||||||
| show_current_events = current_events != None and len(current_events) > 0 | ||||||
| if is_stale or (latest_event["type"] == SCHED_STOP): | ||||||
| show_current_events = False | ||||||
|
|
||||||
| #this current event is only relevant if the latest_event | ||||||
| if (latest_event["type"] and latest_event["type"] == SCHED_STOP): | ||||||
| show_current_events = False | ||||||
| # 4. Handle "Today" vs Date logic | ||||||
| is_today = (readable_date.year == now.year and | ||||||
| readable_date.month == now.month and | ||||||
| readable_date.day == now.day) | ||||||
|
|
||||||
| preface = "Last" | ||||||
| if show_current_events: | ||||||
| preface = "Current" | ||||||
| preface = "Current" if show_current_events else "Last" | ||||||
|
|
||||||
| readable_date = time.from_timestamp(int(int(latest_event["eventDate"]) / 1000.0)).in_location(tz) | ||||||
| line_2 = readable_date.format("Mon Jan 2 at 3:04 PM") | ||||||
| line_3 = "%s: %s - %s" % (preface, latest_event["summary"], readable_date.format("Mon Jan 2 at 3:04 PM")) | ||||||
| line_1 = device_name if show_device_name else "Rachio" | ||||||
| line_2 = readable_date.format("Today at 3:04 PM") if is_today else readable_date.format("Mon, Jan 2 at 3:04 PM") | ||||||
| line_3 = "%s: %s (%s)" % (preface, latest_event["display_type"], readable_date.format("3:04 PM")) | ||||||
| line_4 = "" | ||||||
|
|
||||||
| # 5. Add Zone details if something is currently running | ||||||
| if show_current_events: | ||||||
| current_event = current_events[len(current_events) - 1] | ||||||
| display = current_event["summary"].strip() | ||||||
| if len(display) > 0: | ||||||
| display = "Zone: %s" % display | ||||||
|
|
||||||
| if line_3 == "": | ||||||
| line_3 = display | ||||||
| else: | ||||||
| line_4 = display | ||||||
|
|
||||||
| line_4 = "Zone %d: %s" % (current_event.get("zoneNumber", 0), display) | ||||||
| return render.Root( | ||||||
| render.Column( | ||||||
| children = [ | ||||||
|
|
@@ -238,20 +233,42 @@ def get_events(deviceId, api_key, start, end): | |||||
| return event_response.json() | ||||||
|
|
||||||
| def get_selected_events(tz, events, current): | ||||||
| SUBTYPE_MAP = { | ||||||
| "WEATHER_INTELLIGENCE_SKIP": "Rain Skip", | ||||||
| "WEATHER_INTELLIGENCE_CLIMATE_SKIP": "Soil Saturation Skip", | ||||||
| "WEATHER_INTELLIGENCE_FREEZE_SKIP": "Freeze Skip", | ||||||
| "SCHEDULE_STARTED": "Started", | ||||||
| "SCHEDULE_COMPLETED": "Finished", | ||||||
| } | ||||||
|
|
||||||
| selected_sub_types = [] | ||||||
| if current: | ||||||
| selected_sub_types = [ZONE_STARTED] | ||||||
| else: | ||||||
| selected_sub_types = [SCHED_START, SCHED_STOP, WEATHER_SKIP, WEATHER_CLIMATE_SKIP] | ||||||
|
|
||||||
| selected_events = [] | ||||||
|
|
||||||
| for event in events: | ||||||
| if "subType" in event.keys(): | ||||||
| if event["subType"] in selected_sub_types: | ||||||
| eventDateSecs = time.from_timestamp(int(event["eventDate"] / 1000)).in_location(tz) | ||||||
| parsedDate = eventDateSecs.format("Monday 03:04PM") | ||||||
| newEvent = dict(type = event["subType"], date = parsedDate, summary = event["summary"], eventDate = event["eventDate"]) | ||||||
| selected_events.append(newEvent) | ||||||
| # .get() returns None if the key doesn't exist, preventing a crash | ||||||
| sub_type = event.get("subType") | ||||||
|
|
||||||
| # Now check if the sub_type is one we care about | ||||||
| if sub_type in selected_sub_types: | ||||||
| eventDateSecs = time.from_timestamp(int(event["eventDate"] / 1000)).in_location(tz) | ||||||
| parsedDate = eventDateSecs.format("Monday 03:04PM") | ||||||
| display_name = SUBTYPE_MAP.get(sub_type, sub_type) | ||||||
|
|
||||||
| # Create the dictionary and append | ||||||
| newEvent = dict( | ||||||
| type = sub_type, | ||||||
| display_type = display_name, | ||||||
| date = parsedDate, | ||||||
| summary = event.get("summary", ""), | ||||||
| eventDate = event["eventDate"], | ||||||
| zoneNumber = event.get("zoneNumber", 0), | ||||||
| ) | ||||||
| selected_events.append(newEvent) | ||||||
|
|
||||||
| return selected_events | ||||||
|
|
||||||
|
|
||||||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function
display_error_screenis called with 9 arguments, but its definition only allows for a maximum of 8. The extraicon_widthargument will cause a runtime error. Please remove it from the function call.