Commits

Anonymous committed f99dc88

initial commit

Comments (0)

Files changed (12)

+# use glob syntax.
+syntax: glob
+*.pyc
+*~
+*.DS_Store
+*.kpf
+*.log
+.svn
+*.db
+
+.coverage
+
+virt_*
+
+__pycache__/
+
+ben
+
+\.orig\..*$
+\.orig$
+\.chg\..*$
+\.rej$
+\.conflict\~$
+
+# Ignore IntelliJ (PyCharm) .idea directories and all their contents.
+.idea/
+*.orig
+
+# Ignore eclipse files.
+.project
+.settings
+.pydevproject
+.metadata/
+
+#local settings
+settings_local.py
+CutyCapt.exe
+
+# User media
+uploads/
+
+# Secret stuff
+settings_private.py
+
+# Build dir of docs
+_build/
+__author__ = 'mattotodd'
+#!/usr/bin/env python
+
+import serial
+
+d = """
+1,Arduino ready;
+1,41.90;
+1,68.56;
+"""
+
+class GardenDuino(object):
+    def __init__(self, port, baudrate=115200):
+        self.serial = serial.Serial(port, baudrate)
+        self.ready = False
+        data = self.getData()
+
+    def __str__(self):
+        return "Arduino is on port %s at %d baudrate" %(self.serial.port, self.serial.baudrate)
+
+    def setLow(self, pin):
+        self.__sendData('0')
+        self.__sendData(pin)
+        return True
+
+    def setHigh(self, pin):
+        self.__sendData('1')
+        self.__sendData(pin)
+        return True
+
+    def readOneWireThermo(self, thermo):
+        self.sendData('11,%s;' % (thermo))
+        return float(self.getData()[0])
+
+
+    def sendData(self, serial_data):
+        self.serial.write(str(serial_data))
+
+    def getData(self):
+        line = self.serial.readline().replace('\n', '').replace('\r', '').replace(";", "")
+        parts = line.split(',')
+        if int(parts[0]) == 1:
+            return parts[1:]
+        raise Exception(parts[1])
+
+
+    def __formatPinState(self, pinValue):
+        if pinValue == '1':
+            return True
+        else:
+            return False
+
+    def close(self):
+        self.serial.close()
+        return True

arduino/HotHouseArduinoSketch.ino

+// This serial client for peak farm software based on CmdMessenger's example
+
+// Download these into your Sketches/libraries/ folder...
+
+// CmdMessenger library available from https://github.com/dreamcat4/cmdmessenger
+#include <CmdMessenger.h>
+
+// Base64 library available from https://github.com/adamvr/arduino-base64
+#include <Base64.h>
+
+// Streaming4 library available from http://arduiniana.org/libraries/streaming/
+#include <Streaming.h>
+
+#include<stdlib.h>
+
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into pin 10 on the Arduino
+#define ONE_WIRE_BUS 10
+// set the resolution to 12 mother fucker
+#define THERMO_RESOLUTION 12
+
+// Setup a oneWire instance to communicate with any OneWire devices
+OneWire oneWire(ONE_WIRE_BUS);
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+#define NUM_OF_THERMOS 2
+DeviceAddress thermometers[NUM_OF_THERMOS] = { 
+  { 0x28, 0xDB, 0x9C, 0x37, 0x04, 0x00, 0x00, 0xE4 }, //thermoOne
+  { 0x28, 0x3F, 0x34, 0x63, 0x04, 0x00, 0x00, 0xCA } //thermoTwo
+  //{ 0x28, 0x1D, 0x69, 0x64, 0x04, 0x00, 0x00, 0xED }, //thermoThree
+  //{ 0x28, 0x3A, 0xAC, 0x63, 0x04, 0x00, 0x00, 0xA8 }, //thermoFour
+  //{ 0x28, 0x22, 0xFC, 0x63, 0x04, 0x00, 0x00, 0xC7 }  //thermoFive
+
+};
+
+// Mustnt conflict / collide with our message payload data. Fine if we use base64 library ^^ above
+char field_separator = ',';
+char command_separator = ';';
+
+
+// Attach a new CmdMessenger object to the default Serial port
+CmdMessenger cmdMessenger = CmdMessenger(Serial, field_separator, command_separator);
+
+
+// ------------------ S E R I A L  M O N I T O R -----------------------------
+// 
+// Try typing these command messages in the serial monitor!
+// 
+// 4,hi,heh,ho!;
+// 5;
+// 5,dGhlIGJlYXJzIGFyZSBhbGxyaWdodA==;
+// 5,dGhvc2UgbmFzdHkgY29udHJvbCA7OyBjaGFyYWN0ZXJzICws==;
+// 2;
+// 6;
+// 
+// 
+// Expected output:
+// 
+// 1,Arduino ready;
+// 1,bens cmd recieved;
+// 1,hi;
+// 1,heh;
+// 1,ho!;
+// 1,jerrys cmd recieved;
+// 1,"the bears are allright" encoded in base64...;
+// 1,dGhlIGJlYXJzIGFyZSBhbGxyaWdodA==;
+// 1,jerrys cmd recieved;
+// 1,what you send me, decoded base64...;
+// 1,the bears are allright;
+// 1,jerrys cmd recieved;
+// 1,what you send me, decoded base64...;
+// 1,those nasty control ;; characters ,,;
+// 1,Arduino ready;
+// 3,Unknown command;
+// 
+
+
+// ------------------ C M D  L I S T I N G ( T X / R X ) ---------------------
+
+// We can define up to a default of 50 cmds total, including both directions (send + recieve)
+// and including also the first 4 default command codes for the generic error handling.
+// If you run out of message slots, then just increase the value of MAXCALLBACKS in CmdMessenger.h
+
+// Commands we send from the Arduino to be received on the PC
+enum
+{
+  kCOMM_ERROR    = 000, // Lets Arduino report serial port comm error back to the PC (only works for some comm errors)
+  kACK           = 001, // Arduino acknowledges cmd was received
+  kARDUINO_READY = 002, // After opening the comm port, send this cmd 02 from PC to check arduino is ready
+  kERR           = 003, // Arduino reports badly formatted cmd, or cmd not recognised
+  kFuture1       = 004, // Future Stub
+  kFuture2       = 005, // Future Stub
+  kFuture3       = 006, // Future Stub
+  kFuture4       = 007, // Future Stub
+  kFuture5       = 8, // Future Stub
+  kFuture6       = 9, // Future Stub
+  kFuture7       = 10, // Future Stub
+
+  // Now we can define many more 'send' commands, coming from the arduino -> the PC, eg
+  // kICE_CREAM_READY,
+  // kICE_CREAM_PRICE,
+  // For the above commands, we just call cmdMessenger.sendCmd() anywhere we want in our Arduino program.
+
+  kSEND_CMDS_END, // Mustnt delete this line
+};
+
+// Commands we send from the PC and want to recieve on the Arduino.
+// We must define a callback function in our Arduino program for each entry in the list below vv.
+// They start at the address kSEND_CMDS_END defined ^^ above as 004
+messengerCallbackFunction messengerCallbacks[] = 
+{
+  get_thermo_reading,  // 011
+  bens_msg,  // 012
+  NULL
+};
+// Its also possible (above ^^) to implement some symetric commands, when both the Arduino and
+// PC / host are using each other's same command numbers. However we recommend only to do this if you
+// really have the exact same messages going in both directions. Then specify the integers (with '=')
+
+
+//sullmethods//
+void getTemperatureF(DeviceAddress deviceAddress)
+{ 
+  sensors.requestTemperatures();
+  float tempC = sensors.getTempC(deviceAddress);
+  if (tempC == -127.00) {
+    cmdMessenger.sendCmd(kERR,"error reading temp device");
+  }else{
+    char tempStr[10];
+    dtostrf(DallasTemperature::toFahrenheit(tempC),2,2,tempStr);
+    cmdMessenger.sendCmd(kACK, tempStr);
+  }
+
+}
+
+
+// ------------------ C A L L B A C K  M E T H O D S -------------------------
+
+void bens_msg()
+{
+  // Message data is any ASCII bytes (0-255 value). But can't contain the field
+  // separator, command separator chars you decide (eg ',' and ';')
+  cmdMessenger.sendCmd(kACK,"bens cmd recieved");
+  while ( cmdMessenger.available() )
+  {
+    char buf[350] = { '\0' };
+    cmdMessenger.copyString(buf, 350);
+    if(buf[0])
+      cmdMessenger.sendCmd(kACK, buf);
+  }
+}
+
+void newBoy(int index)
+{
+  sensors.requestTemperatures();
+  char tempStr[10];
+  float celsius = sensors.getTempCByIndex(index);
+  dtostrf(celsius,2,5,tempStr);
+  cmdMessenger.sendCmd(kACK, tempStr);
+}
+
+void get_thermo_reading()
+{
+    if ( cmdMessenger.available() )
+    {
+      char buf[350] = { '\0' };
+      cmdMessenger.copyString(buf, 350);
+      if(buf[0]){
+        getTemperatureF(thermometers[(atoi(buf)-1)]);
+      }else{
+        cmdMessenger.sendCmd(kERR,"error reading thermo params");
+      }
+    }
+  
+}
+
+/*
+void jerrys_base64_data()
+{
+  // To avoid conflicts with the control characters and any newline characters
+  // Message length increases about 30%-40%
+
+  // Afer base64_decode(), we just parse the buffer and unpack it into your
+  // target / desination data type eg bitmask, float, double, whatever.
+  char buf[350] = { '\0' };
+  boolean data_msg_printed = false;
+  cmdMessenger.sendCmd(kACK,"jerrys cmd recieved");
+
+  // base64 decode
+  while ( cmdMessenger.available() )
+  {
+    if(!data_msg_printed)
+    {
+      cmdMessenger.sendCmd(kACK, "what you send me, decoded base64...");
+      data_msg_printed = true;
+    }
+    char buf[350] = { '\0' };
+    cmdMessenger.copyString(buf, 350);
+    if(buf[0])
+    {
+      char decode_buf[350] = { '\0' };
+      base64_decode(decode_buf, buf, 350);
+      cmdMessenger.sendCmd(kACK, decode_buf);
+    }
+  }
+
+  // base64 encode
+  if(!data_msg_printed)
+  {
+    cmdMessenger.sendCmd(kACK, "\"the bears are allright\" encoded in base64...");
+    char base64_msg[350] = { '\0' };
+    base64_encode(base64_msg, "the bears are allright", 22);
+    cmdMessenger.sendCmd(kACK, base64_msg);
+  }
+}
+*/
+// ------------------ D E F A U L T  C A L L B A C K S -----------------------
+
+void arduino_ready()
+{
+  // In response to ping. We just send a throw-away Acknowledgement to say "im alive"
+  cmdMessenger.sendCmd(kACK,"Arduino ready");
+}
+
+void unknownCmd()
+{
+  // Default response for unknown commands and corrupt messages
+  cmdMessenger.sendCmd(kERR,"Unknown command");
+}
+
+// ------------------ E N D  C A L L B A C K  M E T H O D S ------------------
+
+
+
+// ------------------ S E T U P ----------------------------------------------
+
+void attach_callbacks(messengerCallbackFunction* callbacks)
+{
+  int i = 0;
+  int offset = kSEND_CMDS_END;
+  while(callbacks[i])
+  {
+    cmdMessenger.attach(offset+i, callbacks[i]);
+    i++;
+  }
+}
+
+void setup() 
+{
+  // Listen on serial connection for messages from the pc
+  // Serial.begin(57600);  // Arduino Duemilanove, FTDI Serial
+  Serial.begin(115200); // Arduino Uno, Mega, with AT8u2 USB
+
+  // cmdMessenger.discard_LF_CR(); // Useful if your terminal appends CR/LF, and you wish to remove them
+  cmdMessenger.print_LF_CR();   // Make output more readable whilst debugging in Arduino Serial Monitor
+  
+  // Attach default / generic callback methods
+  cmdMessenger.attach(kARDUINO_READY, arduino_ready);
+  cmdMessenger.attach(unknownCmd);
+
+  // Attach my application's user-defined callback methods
+  attach_callbacks(messengerCallbacks);
+
+  arduino_ready();
+
+  // blink
+  pinMode(13, OUTPUT);
+  
+  // Start up the OneWire sensor library
+  sensors.begin();
+  for (int thermo_i=0; thermo_i < NUM_OF_THERMOS; thermo_i++){
+     sensors.setResolution(thermometers[thermo_i], THERMO_RESOLUTION);
+  }
+}
+
+
+// ------------------ M A I N ( ) --------------------------------------------
+
+// Timeout handling
+long timeoutInterval = 2000; // 2 seconds
+long previousMillis = 0;
+int counter = 0;
+
+void timeout()
+{
+  // blink
+  if (counter % 2)
+    digitalWrite(13, HIGH);
+  else
+    digitalWrite(13, LOW);
+  counter ++;
+}  
+
+void loop() 
+{
+  // Process incoming serial data, if any
+  cmdMessenger.feedinSerialData();
+
+  // handle timeout function, if any
+  if (  millis() - previousMillis > timeoutInterval )
+  {
+    timeout();
+    previousMillis = millis();
+  }
+
+  // Loop.
+}
+
+from datetime import timedelta
+import _
+from mongoengine import *
+from flask import Flask, render_template, jsonify, request, redirect
+from flask.helpers import make_response
+from webassets.loaders import PythonLoader as PythonAssetsLoader
+from flask.ext.assets import Environment as AssetsEnvironment
+
+import settings, models, auth, assets
+
+VERSION = "0.1"
+
+app = Flask(__name__)
+
+assets_env = AssetsEnvironment(app)
+assets_env.config["less_bin"] = "/usr/bin/less"
+assets_loader = PythonAssetsLoader(assets)
+for name, bundle in assets_loader.load_bundles().iteritems():
+    assets_env.register(name, bundle)
+
+# Connect to the database
+conn = connect(settings.MONGONAME, host=settings.MONGOHOST)
+
+#conn = connect(settings.MONGONAME, host="ds031407.mongolab.com", port=31407, username="farmer", password="aquaponics")
+
+@app.before_request
+def capture_effective_data():
+
+    if not hasattr(request, 'effective_method'):
+        request.effective_method = request.method
+
+    effective_data = dict()
+    if request.values:
+        for k, v in request.values.items():
+            effective_data[k] = v
+    if request.mimetype == "application/xml":
+        request.effective_data = request.data
+    if request.json:
+        for k, v in request.json.items():
+            effective_data[k] = v
+    request.effective_data = effective_data
+
+# Auth Urls
+@app.route('/check_yourself', methods=['POST','GET'])
+def login():
+
+    form = request.effective_data
+    try:
+        user = auth.login(form['username'], form['password'])
+        return jsonify(ok=True, user=user.to_dict(deep=settings.DEPTH_FULL))
+    except (auth.UnknownUsername, auth.IncorrectPassword):
+        return jsonify(error="Bad Username or Password")
+    except Exception, e:
+        notify_admins("Error logging in for: " + form['username'] + ": " + e.message)
+        return jsonify(error="Server Error")
+
+@app.route('/register', methods=['POST', 'GET'])
+def register():
+    form = request.effective_data
+    #first we wanna see if we can log them in
+    try:
+        user = auth.login(form['email'], form['password'])
+        #username and password match, lets let them in
+        return jsonify(ok=True, user=user.to_dict())
+    except:
+        #if login fails, continue with registration
+        try:
+            source = form.get('source', None)
+            query_str = form.get('query_string', None)
+            user = auth.register(form['email'], form['full_name'], form['password'], source=source, query_string=query_str)
+            return jsonify(ok=True, user=user.to_dict())
+
+        except auth.InvalidSignupKey:
+            error="Invalid Invitation Code"
+        except auth.UsernameExists:
+            error="Username Exists"
+        except auth.EmailExists:
+            error="Email Exists"
+        except auth.InvalidUsername:
+            error="Invalid Username"
+        except auth.InvalidPassword:
+            error="Invalid Password"
+        except auth.InvalidEmail:
+            error="Invalid Email"
+        except Exception, e:
+            return jsonify(error="Server Error")
+
+
+@app.route('/logout', methods=['GET'])
+def logout():
+    auth.logout()
+    if request.is_xhr:
+        return jsonify(ok=True)
+    else:
+        return redirect('/')
+
+@app.route('/logged_in', methods=['GET'])
+def logged_in():
+    if not settings.LOGGED_IN_USER():
+        resp = make_response(jsonify(logged_in=False))
+    else:
+        auth.determine_user_visit(request)
+        user_dict = request.user.to_dict(deep=settings.DEPTH_FULL)
+        resp = make_response(jsonify(logged_in=True, user=user_dict, apiKey=auth.generate_api_key(request.user)))
+
+    resp.cache_control.no_cache = True
+    return resp
+
+@app.route("/graph_data")
+def graph_stub():
+    temps = models.Reading.objects(garden_id="sully_test").limit(120).order_by("-created_on")
+    temps = reversed(temps)
+    outside = []
+    inside = []
+    timestamps = []
+    for r in temps:
+        outside.append(r.outside_temp_F)
+        inside.append(r.inside_temp_F)
+        timestamps.append(_.datetime_to_javascript_timestamp(r.created_on-timedelta(hours=5)))
+    return jsonify(data={
+        'outside':outside,
+        'inside':inside,
+        'timestamps':timestamps
+    })
+
+
+@app.route("/current")
+def current():
+    current = models.Reading.objects.all().order_by('-created_on').first()
+
+    return jsonify(result={
+        'recorded':_.datetime_to_javascript_timestamp(current.created_on),
+        'tempF':current.temp_F,
+        'humidity':current.humidity if current.humidity < 100 else None
+    })
+
+
+@app.route('/vid', methods=['GET', 'POST'])
+def vv():
+    return make_response(render_template('video.html'))
+
+@app.route('/', methods=['GET'])
+@app.route('/<path:path>', methods=['GET', 'POST'])
+def main_app(path=None):
+    return make_response(render_template('manager/manager.html'))
+
+
+
+if __name__ == '__main__':
+    import argparse
+    import os, sys
+    sys.path.append(os.path.realpath(os.path.dirname(__file__)))
+
+    parser = argparse.ArgumentParser(description='peak farm management server %s' % (VERSION, ),
+        epilog="a mattotodd project")
+    parser.add_argument("-d", "--debug", action="store_true", dest="debug_mode",
+        help="run in debug mode (for use with PyCharm)", default=False)
+    parser.add_argument("-p", "--port", dest="port",
+        help="port of server (default:%(default)s)", type=int, default=5000)
+    parser.add_argument("-c", "--host", dest="host",
+        help="host of server (default:%(default)s)", type=str, default="127.0.0.1")
+
+    cmd_args = parser.parse_args()
+
+    settings.APP_DOMAIN = cmd_args.host
+    settings.APP_PORT = cmd_args.port
+
+    app_options = {
+        "host": settings.APP_DOMAIN,
+        "port": settings.APP_PORT
+    }
+
+    if cmd_args.debug_mode:
+        app_options["debug"] = True
+        app_options["use_debugger"] = False
+        app_options["use_reloader"] = False
+
+    app.run(**app_options)
+__author__ = 'sully'

gpio/numato_lab.py

+import serial
+
+portName = "/dev/tty.usbmodemfa131"
+
+def set_gpio(gpioNum, high=True):
+    command = "set" if high else "clear"
+    #Open port for communication
+    serPort = serial.Serial(portName, 19200, timeout=1)
+    #Send the command
+    serPort.write("gpio "+ command +" "+ str(gpioNum) + "\n\r")
+    #Close the port
+    serPort.close()
+from mongoengine import *
+from datetime import datetime
+
+class Input(object):
+    def __init__(self, label, data_type=str):
+        self.label = label
+        self.__type__ = data_type
+
+    @property
+    def type(self):
+        return self.__type__
+
+class Sensor(object):
+    pass
+from arduino import GardenDuino
+#from models import Reading
+import settings
+
+#garden = GardenDuino(settings.ARDUINO_DEVICE_PATH)
+
+def run_check():
+    """
+    r = Reading(
+        garden_id = "sully_test",
+        outside_temp_F = self.garden.readOneWireThermo(2),
+        inside_temp_F = garden.readOneWireThermo(1)
+    )
+    r.save()
+    """
+    print "Checked"
+from mongoengine import *
+from datetime import datetime
+
+class Sensor(object):
+    def __init__(self, label, data_type=str):
+        self.label = label
+        self.__type__ = data_type
+
+    @property
+    def type(self):
+        return self.__type__
+
+class Reading(Document):
+    created_on = DateTimeField(default=datetime.now)
+    garden_id = StringField()
+    inside_temp_F = FloatField()
+    outside_temp_F = FloatField()
+
+#from sqlalchemy import create_engine
+#engine = create_engine('sqlite:///:memory:', echo=True)
+import socket, urlparse
+from datetime import datetime
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+from BaseHTTPServer import HTTPServer
+import manager
+
+import settings
+
+class HotHouseRequestHandler(SimpleHTTPRequestHandler):
+    def do_GET(self):
+        parsedParams = urlparse.urlparse(self.path)
+        queryParsed = urlparse.parse_qs(parsedParams.query)
+
+        if parsedParams.path == "/update":
+            print "Manual Check Triggered"
+            self.server.begin_check()
+            self.processMyRequest("ok")
+        else:
+            self.processMyRequest("unknown command")
+
+        self.server.get_request() #required to trigger next timeout
+
+    def do_POST(self):
+        self.send_response(405)
+        self.server.get_request() #required to trigger next timeout
+
+    def processMyRequest(self, status):
+
+        self.send_response(200)
+        self.send_header('Content-Type', 'application/json')
+        self.end_headers()
+
+        self.wfile.write('{status:"%s"}' % (status,))
+        self.wfile.close()
+
+class HotHouseServer(HTTPServer):
+
+    def server_bind(self):
+        HTTPServer.server_bind(self)
+        self.socket.settimeout(1.0)
+        self.run = True
+
+    def get_request(self):
+        while self.run:
+            try:
+                sock, addr = self.socket.accept()
+                sock.settimeout(None)
+                return (sock, addr)
+            except socket.timeout:
+                print "Regular Check Triggered"
+                self.begin_check()
+
+    def stop(self):
+        self.run = False
+
+    def begin_check(self):
+        self.begin_check = datetime.now()
+        try:
+            manager.run_check()
+        except Exception as e :
+            raise
+
+        self.completed_check = datetime.now()
+        check_length = (self.completed_check - self.begin_check)
+        if check_length.total_seconds() > settings.CHECK_INTERVAL:
+            self.socket.settimeout(0.1)
+        else:
+            new_timeout = float(settings.CHECK_INTERVAL) - float(check_length.total_seconds())
+            self.socket.settimeout(new_timeout)
+
+
+    def serve(self):
+        self.get_request() #required to trigger a timeout
+        while self.run:
+            self.handle_request()
+
+
+if __name__=="__main__":
+    httpd = HotHouseServer((settings.HOST, settings.PORT), HotHouseRequestHandler)
+    httpd.serve()
+import os, sys
+
+PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
+
+def local(path):
+    return os.path.join(PROJECT_PATH, path)
+
+INSTANCE_NAME = "hothouse"
+LOCAL_SQLITE_DB = "%s.db" % (INSTANCE_NAME,)
+
+HOST = "127.0.0.1"
+PORT = 8082
+
+CHECK_INTERVAL = 60
+
+ARDUINO_DEVICE_PATH = "/dev/ttyACM1"