Some guidance???
Some background:
I use my Linode for primarily hosting numerous websites and providing VPN's for friends overseas.
Semi recently I was toying around, and used an Arduino to control my detached garage door. It uses relays for the open close functionality, and a combination of limit switches and magnetic switches for the feedback of the door positions.
I currently use a raspberry PI on my home network that is reachable from the outside via https which can talk to the Arduino over Ethernet. I put together a small PHP script that allows me to check the status of the door, as well as operate it. This was about the extent of my php scripting.
My Linode runs a bash script ever 5 minutes that checks the door status, if the door is open, it write a value to a text file. If on the next check it is still open (checks the text file), if will send me a text letting me know that I left the door open.
Where I need some help:
I have wanted to clean all of this up for a while, but really don’t know the best way to do it as I really am not much of a programmer. Ideally, I want to start to use a database to track the number of minutes the garage door is open so I don’t get a text if it is open for 2 scans of the script, which could be 5 minutes and 1 second.
I was also thinking it would be handy to have a way (via url) that could "set an alarm" (bit in db) where if it detects an open door it would text immediately instead of waiting. I would also want to be able to disable the alarm the same way. Maybe something like
Is it easy to integrate a bash script with mysql?
I don't think that anything here is too hard, but I just want to do it in the most efficient way possible.
Any advice or questions? This is more for my own learning than anything else.
3 Replies
~~![](<URL url=)http://drop.hoopycat.com/garage_state_machine.jpg
I think the Arduino is actually the easier place to put the state machine, because otherwise you have to deal with all the orchestrations required to maintain less than 8 bits of state in a stateless HTTP-based system. When STATUS changes, have it send a signal to the RPi that causes it to e-mail you or whatever. I'd also set up a mechanism on the Arduino to query STATUS, as well as set or clear the ARMED flag… a RESET is probably also a good idea (when this happens, go straight back to START).
Note: I haven't tested this code, nor have I written a state machine in C before. God help you.
typedef enum {ST_IDLE, ST_OPEN, ST_WAIT, ST_ALARMING} state_t;
typedef enum {ALLCLEAR, PANIC, DUMBADOLLARSIGNDOLLARSIGN} status_t;
typedef enum {false = 0, true} bool; // good god, what a barbaric language
state_t currentState = ST_IDLE;
status_t currentDoorStatus = ALLCLEAR;
const unsigned long OPEN_WAIT = 5 * 60 * 1000; // milliseconds to wait when the barn door is open
unsigned long open_millis = 0; // millis() when door is detected open
bool armed = false; // set this to true if you want to PANIC
// prototypes for implementation-specific stuff
void sendNotification(status_t alarmStatus);
bool isGarageDoorOpen();
// setStatus: calls sendNotification when newStatus is different than currentDoorStatus
void setStatus(status_t newStatus)
{
if (newStatus != currentDoorStatus)
{
// the status has changed; send a text message or e-mail or whatever
sendNotification(newStatus);
currentDoorStatus = newStatus;
}
return;
}
// loop: this is the code that loops over and over and over again
void loop()
{
switch (currentState)
{
case ST_IDLE:
if (true == isTheGarageDoorOpen())
{
// garage door is open; proceed to open state
currentState = ST_OPEN;
}
else
{
// garage door is closed; all clear, stay in idle state
setStatus(ALLCLEAR);
currentState = ST_IDLE;
}
break;
case ST_OPEN:
if (true == armed)
{
// alarm is armed, freak all the way out, proceed to alarming state
setStatus(PANIC);
currentState = ST_ALARMING;
}
else
{
// alarm is not armed, record current time, proceed to wait state
open_millis = millis(); // record the current time
currentState = ST_WAIT;
}
break;
case ST_WAIT:
if (OPEN_WAIT < (millis() - open_millis))
{
if (true == isTheGarageDoorOpen())
{
// door has been open more than OPEN_WAIT milliseconds, update status and proceed to alarming state
setStatus(DUMBADOLLARSIGNDOLLARSIGN);
currentState = ST_ALARMING;
}
else
{
// miracles of miracles; the damn thing is now closed. back to idle state
currentState = ST_IDLE;
}
}
else
{
// continue waiting...
currentState = ST_WAIT;
}
break;
case ST_ALARMING:
if (false == isTheGarageDoorOpen())
{
// garage door has closed, return to idle state
currentState = ST_IDLE;
}
else
{
// we're still freaking out over here
currentState = ST_ALARMING;
}
break;
}
}
Edit: So apparently I hallucinated the bool type; I tend to do that. Have another enum.~~