/raspberrypi_growlight

Small flask server to control my dwarf citrus tree's growlight with a raspberrypi so that it turns on at sunrise and turns off at sunset.

Primary LanguageJupyter NotebookApache License 2.0Apache-2.0

# default_exp raspberrypi_growlight

This is a simple bare-bones webserver run on my raspberry pi to turn my dwarf citrus tree's grow light on at sunrise and off at sunset.

Imports

# export
import datetime
import sys
import time

import apscheduler.schedulers.background
import astral
import astral.sun
import pytz
import RPi.GPIO as GPIO
from flask import Flask

Config

Raspberry Pi

# export
PIN_GPIO = 17
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)         # Broadcom Chip
GPIO.setup(PIN_GPIO, GPIO.OUT) # Output 

Test out gpio stuff manually

GPIO.output(PIN_GPIO, True)
GPIO.output(PIN_GPIO, False)

Timezone

Needed to localize datetime.now()

# export
TIMEZONE = pytz.timezone('US/Eastern')

Server

Set interval in seconds to check schedule

# export
INTERVAL = 1

Growlight

Growlight on() will turn on grow light and off() will turn off grow light

# export
class Growlight:
    def on(self):
        GPIO.output(PIN_GPIO, True)
    
    def off(self):
        GPIO.output(PIN_GPIO, False)

Test to see if growlight turns on and off

growlight = Growlight()
growlight.on()
time.sleep(1)
growlight.off()

Schedule

Given an input time, Schedule will return 'ON' if grow light should be on and 'OFF' if growlight should be off

# export
class Schedule:
    def get_status(T):
        return 'OFF' 

Sunlight schedule will turn on during sunlight

# export
class SunlightSchedule(Schedule):
    def __init__(self, city):
        self.city = city
        
    def get_status(self, T):
        s = astral.sun.sun(self.city.observer) # Get current status of sun
        if s['sunrise'] < T < s['sunset']: return 'ON'
        else:                              return 'OFF'
    
    def __repr__(self):
        return f'sunlight schedule for {self.city.name}.'

Make a schedule based on lowell

# export
class LowellSunlightSchedule(SunlightSchedule):
    def __init__(self):
        super().__init__(city=astral.LocationInfo(name='Lowell',
                                                  region='USA',
                                                  timezone='Eastern',
                                                  latitude=42.640999,  
                                                  longitude=-71.316711))

Test out schedule

schedule = LowellSunlightSchedule()
schedule
sunlight schedule for Lowell.
T = TIMEZONE.localize(datetime.datetime.now())
schedule.get_status(T)
'ON'

Add some time to see if scheduler works

schedule.get_status(T + datetime.timedelta(hours=10))
'OFF'

GrowlightScheduler

Given a Schedule and a GrowLight, GrowlightScheduler will turn on or off the growlight based on the schedule at a given interval.

# export
class GrowlightScheduler:
    def __init__(self, schedule, growlight, interval=INTERVAL):
        self.schedule  = schedule
        self.growlight = growlight
        self.interval  = interval
        self.scheduler = apscheduler.schedulers.background.BackgroundScheduler()
        self.scheduler.add_job(self.job, 'interval', seconds=self.interval)
        
    def job(self):
        T = TIMEZONE.localize(datetime.datetime.now())
        status = self.schedule.get_status(T)
        if   status == 'ON':  self.growlight.on()
        elif status == 'OFF': self.growlight.off()
        else:                 raise RuntimeError(f'Unknown status: {status}')
    
    def start(self):
        if self.scheduler.running: self.scheduler.resume()
        else:                      self.scheduler.start()    
        
    def stop(self):
        if self.scheduler.running: self.scheduler.pause()
schedule = LowellSunlightSchedule()
growlight = Growlight()
scheduler_growlight = GrowlightScheduler(schedule, growlight)
scheduler_growlight.start()
scheduler_growlight.stop()
growlight.off()

Flask app

Create flask app with the following API:

  • ON - stops scheduler and turns growlight on
  • OFF - stops scheduler and turns growlight off
  • START - starts scheduler
  • STOP - stops scheduler
  • STATUS - returns current status
# export
app = Flask(__name__)
schedule = LowellSunlightSchedule()
growlight = Growlight()
scheduler_growlight = GrowlightScheduler(schedule, growlight)
STATUS = None
# export
def _status():
    return f'Growlight status: {STATUS}'
# export
@app.route('/ON/', methods=['GET'])
def ON():
    global STATUS
    scheduler_growlight.stop()
    growlight.on()
    STATUS = 'ON'
    return _status()
# export
@app.route('/OFF/', methods=['GET'])
def OFF():
    global STATUS
    scheduler_growlight.stop()
    growlight.off()
    STATUS = 'OFF'
    return _status()
# export
@app.route('/START/', methods=['GET'])
def START():
    global STATUS
    scheduler_growlight.start()
    STATUS = str(scheduler_growlight.schedule)
    return _status()
# export
@app.route('/STOP/', methods=['GET'])
def PAUSE(): 
    global STATUS
    scheduler_growlight.stop()
    STATUS = 'stopped ' + str(scheduler_growlight.schedule)
    return _status()
# export
@app.route('/STATUS/', methods=['GET'])
def STATUS():
    return _status()

For testing purposes change name

__name__ = '__notebook__'

By default, start grownlight scheduler when server starts up

# export
if __name__ == '__main__':
    START()
    app.run(host='0.0.0.0', port=8080)

Build

!nbdev_build_lib --fname raspberrypi_growlight.ipynb
Converted raspberrypi_growlight.ipynb.
!jupyter nbconvert --to markdown --output README raspberrypi_growlight.ipynb
[NbConvertApp] Converting notebook raspberrypi_growlight.ipynb to markdown
[NbConvertApp] Writing 6159 bytes to README.md