biophysics • learned Django at hackathon where WattTime started • now co-founder and CTO at WattTime (shoutout to UnconsciousBiasProject.org @UBP_STEM)
location Device name location Device name location Observation value device timestamp Observation value device timestamp Observation value device timestamp
vendor ID Device name location vendor ID Device name location vendor ID Observation value device timestamp Observation value device timestamp Observation value device timestamp ☕️ vendor’s unique ID(s) whatever data you need to send to their API
device timestamp the IoT app Observation value device timestamp Device name location vendor ID Device name location vendor ID Device name location vendor ID use db_index you’ll be sorting on this a lot! Observation value device timestamp Observation value device timestamp Observation value device timestamp Observation value device timestamp Observation value device timestamp Observation value device timestamp Observation value device timestamp Observation value device timestamp
device timestamp the IoT app Attribute value units device timestamp Device name location vendor ID Device name location vendor ID Device name location vendor ID Attribute vs Status numerical vs str/bool values Observation value device timestamp Observation value device timestamp Observation value device timestamp Attribute value units device timestamp Observation value device timestamp Observation value device timestamp Observation value device timestamp Attribute value units device timestamp Observation value device timestamp Observation value device timestamp Observation value device timestamp Status is_on device timestamp ☕️
Device.objects.get( pk=device_id ) # get status from device client is_on = client.get_status(device) # create status status = device.status_set.create( is_on=is_on, valid_at=timezone.now(), ) # return return [status.pk] pass pks pro: don’t rely on database state con: may be extra queries
models.py admin.py views.py tests.py why not client as Device model methods? works ok, but less reusable and less scalable device.send_status_to_vendor()
servers worker servers messages tasks tasks messages results result store or or Django ORM (djcelery) or None tasks scheduler Celery architecture (how)
use the actual path 'task': 'path.to.task', # every 5 minutes 'schedule': crontab(minute='*/5'), # args and kwargs 'args': [], 'kwargs': {}, }, } schedule.py very close to crontab once per minute - once per year (when)
use the actual path 'task': 'path.to.task', # every 5 minutes 'schedule': crontab(minute='*/5'), # args and kwargs 'args': [], 'kwargs': {'device_id': d.pk}, } for d in Device.objects.all() } schedule.py static arguments only code is only evaluated once at run time, better to have one task spawn daughters (when)
make celery app available to @shared_task, and to Procfile __init__.py web: gunicorn django_iot.wsgi --log-file - scheduler: celery worker -B -A django_iot worker: celery worker -A django_iot Procfile -B for beat worker and scheduler in one! warning!! with free Heroku dynos, scheduler sleeps if web dyno is inactive for 30 min
outside request/response • ☕️ easy but rigid: Heroku Scheduler • flexible but complex: celery periodic tasks • hack better+faster: cookiecutter-django-iot • IoT can be for good, not just for fun and profit what have we learned?