Skip to content

Instantly share code, notes, and snippets.

@drewrothstein
Created June 28, 2021 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drewrothstein/4e7c4f8aee19d8297a35561fbe4806ef to your computer and use it in GitHub Desktop.
Save drewrothstein/4e7c4f8aee19d8297a35561fbe4806ef to your computer and use it in GitHub Desktop.
Automower Action Data
#!/usr/bin/python3
import datetime
import time
from shapely import geometry
import geopandas as gpd
import pandas as pd
import requests
import timeago
MOWER_NAME = 'Fred'
# Source: github.com/chrisz/pyhusmow
# ./husmow --login <> --password <> server
DATA_API = 'http://127.0.0.1:1234/status'
TIME_BETWEEN_CHECKS_SECONDS = 30
# API to Save Location
SAVE_API = 'https://us-central1-<XXXXXXX TODO XXXXXXX>.cloudfunctions.net/automower'
# Counter-clockwise Boundary Boxes: [(Bottom-left), (Bottom-right), (Top-right), (Top-left)]
CRS = {'init': 'epsg:4326'} # https://epsg.io/4326
# XXXXXXX TODO XXXXXXX
AREA_HILL = [(41.049734, -33.577369),(41.049750, -33.897128),(41.050419, -33.897219),(41.050417, -33.867487)]
AREA_PATH = [(41.049734, -33.857120), (41.049824, -33.875063), (41.049949, -33.896138), (41.049873, -33.897168)]
AREA_FRONT = [(41.049895, -33.896023), (41.049861, -33.895808), (41.050236, -33.894636), (41.050300, -33.896102)]
AREA_SIDE = [(45.050226, -33.895870), (45.050238, -33.895608), (45.046371, -33.895570), (45.050379, -33.856948)]
AREA_BACK = [(45.049804, -33.874686), (45.049839, -33.895298), (45.050329, -33.895336), (45.050242, -33.895623)]
def save_automower_location(message):
params = {'message': message}
r = requests.post(SAVE_API, params=params)
r.raise_for_status()
def get_mower_status():
r = requests.get(DATA_API)
# 1624880445224
timestamp = r.json()['storedTimestamp']
# [{'latitude': 87.0499532, 'longitude': -89.8958507, 'gpsStatus': 'USING_GPS_MAP'}]
location = r.json()['lastLocations']
# {'latitude': 87.0499532, 'longitude': -89.8958507, 'gpsStatus': 'USING_GPS_MAP'}
loc0 = location[0]
# 100
battery = r.json()['batteryPercent']
# OK_LEAVING
status = r.json()['mowerStatus']
return timestamp, loc0, battery, status
def convert_timestamp_to_human(timestamp):
now = datetime.datetime.now()
timestamp_seconds = timestamp / 1000.0
date = datetime.datetime.fromtimestamp(timestamp_seconds)
return (timeago.format(date, now))
def check_automower_in_box(location, point_list):
in_box = False
poly = geometry.Polygon(point_list)
spoly = gpd.GeoSeries([poly],crs=CRS)
geo_data = [geometry.Point(location['latitude'], location['longitude'])]
dfpoints = gpd.GeoDataFrame(crs=CRS, geometry=geo_data)
subset = dfpoints[dfpoints.within(spoly.geometry.iloc[0])]
if subset.shape[0] > 0:
in_box = True
return in_box
def main():
# 1624880445224, {'latitude': 89.0499532, 'longitude': -100.8958507, 'gpsStatus': 'USING_GPS_MAP'}, 100, 'OK_LEAVING'
timestamp, location, battery, status = get_mower_status()
# Examples: 25 seconds ago, just now
timestamp_human_formatted = convert_timestamp_to_human(timestamp)
# Check each boundary
message = ''
if 'PARK' in status or 'CHARG' in status:
message = '{0} is charging with {1} percent battery'.format(MOWER_NAME, battery)
elif check_automower_in_box(location, AREA_HILL):
message = '{0} is on the front hill as of {1} with {2} percent battery'.format(MOWER_NAME, timestamp_human_formatted, battery)
elif check_automower_in_box(location, AREA_PATH):
message = '{0} is on the front path to the hill as of {1} with {2} percent battery'.format(MOWER_NAME, timestamp_human_formatted, battery)
elif check_automower_in_box(location, AREA_FRONT):
message = '{0} is in the front of the house as of {1} with {2} percent battery'.format(MOWER_NAME, timestamp_human_formatted, battery)
elif check_automower_in_box(location, AREA_SIDE):
message = '{0} is on the side of the house as of {1} with {2} percent battery'.format(MOWER_NAME, timestamp_human_formatted, battery)
elif check_automower_in_box(location, AREA_BACK):
message = '{0} is in the back of the house as of {1} with {2} percent battery'.format(MOWER_NAME, timestamp_human_formatted, battery)
else:
message = '{0} is not able to be located as of {1}'.format(MOWER_NAME, timestamp_human_formatted)
save_automower_location(message)
while True:
main()
time.sleep(TIME_BETWEEN_CHECKS_SECONDS)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment