Non e' un progetto definitivo, ma e' ancora tutto nella mia testa.
Comunque:
- capacita' di pilotare fino 8 rele per le prese comandate.
- memorizzazione dello stato di ogni singolo relay.
- gestione via web client side. (Penso che il client sara' realizzato in java per superare le limitazioni della "same-origin policy"Cross-Domain, ma magari trovo l'uovo di colombo ).
Attualmente l'intefaccia risponde a query nel formato <ip>/?pin=P&val=V (P=numero pin dell'Arduino da 2 a 9 e V=valore 0/1) e ritorna una risposta testuale alla chiamata.
Con <ip> senza parametri viene restituita una stringa con lo status di tutte le linee digitali gestite (da 2 a 9, le 10,11,12,13 sono riservati per la gestione dello shied 28J60).
Ho realizzato tutto prendendo spunto qua e la, con uno shield ENC28J60 ed un arduino carrozzato con un atmega8/optiboot
Rimangono 1k per la programmmazione, ma l'output seriale non funziona probabilmente per problemi di buffer (l'A8 ha solo un 1k ram, mentre 328 ne ha 2k ).
No JSONP, no librerie troppo server side che rendono la vita semplice ma occupano inutilmente la memoria dell'atmega.
[AGGIORNAMENTO 28-01-2013]
Sono riuscito ad effettuare chiamate da webclient con risposte tramite CORS. Quindi l'interfaccia sara' una semplice pagina html.
Voglio implementare un timer per forzare lo spegnimento delle prese in 'tot' minuti, questo per consentirmi lo shutdown del pc, al resto poi ci pensera' l'Arduino.
Stesura prima versione.
Codice: Seleziona tutto
#include "EtherShield.h"
// Default CS pin is 10, for the unmodified shield.
// Can be changed in init function to use another pin
// define DEFAULT_ENC28J60_CONTROL_CS 10
// define SPI_MOSI 11
// define SPI_MISO 12
// define PI_SCK 13
// http://192.168.1.15/?pin=2&val=1
// pin da 2 a 9
//
// EEPROM
#include <EEPROM.h>
// ID of the settings block
#define CONFIG_VERSION "v01"
// Tell it where to store your config data in EEPROM
#define CONFIG_START 32
#define SET_EEPROM 1
//#define SERIAL_LOG 1
static byte mymac[6] = {
0x54,0x55,0x58,0x10,0x00,0x25};
static byte myip[4] = {
192,168,1,15};
static byte gwip[4] = {
192,168,1,1};
// listen port for tcp/www:
#define MYWWWPORT 80
#define BUFFER_SIZE 650
static byte buf[BUFFER_SIZE+1];
static char status[11] = {'0','0','0','0','0','0','0','0','\r','\n','\0' };
static char setpin[10] = {'p','=',' ','&','v','=',' ','\r','\n','\0' };
EtherShield es= EtherShield();
// eeprom
struct StoreStruct {
// The variables of your settings
byte pins[8];
// This is for mere detection if they are your settings
char versione[4];
} settings = {
// The default values
{LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW},
CONFIG_VERSION
};
int pinvalue;
char kvalstrbuf[10];
int8_t analyse_get_url(char *str)
{
byte mn=0;
if (es.ES_find_key_val(str,kvalstrbuf,10,"pin")) {
mn=1;
//Serial.println(kvalstrbuf); //prints value to serial
pinvalue = atoi(kvalstrbuf);
//?pin=<N>
//Serial.println(kvalstrbuf); //prints value to serial
es.ES_find_key_val(str,kvalstrbuf,10,"val");
//?val=<0:1>
}
return(mn);
}
uint16_t http200ok(void)
{
return(es.ES_fill_tcp_data_p(buf,0,PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nPragma: no-cache\r\n\r\n")));
}
void saveConfig() {
for (unsigned int t=0; t<sizeof(settings); t++)
{ // writes to EEPROM
EEPROM.write(CONFIG_START + t, *((char*)&settings + t));
// and verifies the data
if (EEPROM.read(CONFIG_START + t) != *((char*)&settings + t))
{
#ifdef SERIAL_LOG
Serial.println("errore, salvando le impostazioni");
#endif
// error writing to EEPROM
}
}
}
void loadConfig() {
// To make sure there are settings, and they are YOURS!
// If nothing is found it will use the default settings.
if (//EEPROM.read(CONFIG_START + sizeof(settings) - 1) == settings.version_of_program[3] // this is '\0'
EEPROM.read(CONFIG_START + sizeof(settings) - 2) == settings.versione[2] &&
EEPROM.read(CONFIG_START + sizeof(settings) - 3) == settings.versione[1] &&
EEPROM.read(CONFIG_START + sizeof(settings) - 4) == settings.versione[0])
{ // reads settings from EEPROM
for (unsigned int t=0; t<sizeof(settings); t++)
*((char*)&settings + t) = EEPROM.read(CONFIG_START + t);
} else {
#ifdef SERIAL_LOG
Serial.println("dati errati in caricamento, salvo impostazioni");
#endif
// settings aren't valid! will overwrite with default settings
saveConfig();
}
}
void setup()
{
#ifdef SERIAL_LOG
Serial.begin(9600);
#endif
// carica stato pin dalla eeprom interna
#ifdef SET_EEPROM
loadConfig();
#endif
// setta le porte dei pin in output e carica stato dalla eeprom
for (byte pin = 2; pin < 10; pin++) {
pinMode(pin, OUTPUT);
#ifdef SET_EEPROM
digitalWrite(pin, settings.pins[pin-2]); // set the LED on
delay(20);
#endif
}
/*initialize enc28j60*/
es.ES_enc28j60Init(mymac);
//init the ethernet/ip layer:
es.ES_init_ip_arp_udp_tcp(mymac,myip, MYWWWPORT);
// init the web client:
es.ES_client_set_gwip(gwip); // e.g internal IP of dsl router
}
void loop(){
uint16_t dat_p;
int8_t cmd;
byte flag_err = false;
while(1)
{
// handle ping and wait for a tcp packet
dat_p=es.ES_packetloop_icmp_tcp(buf,es.ES_enc28j60PacketReceive(BUFFER_SIZE, buf));
if(dat_p==0){
continue;
}
if (strncmp("GET ",(char *)&(buf[dat_p]),4)!=0){
dat_p=http200ok();
goto SENDTCP;
}
cmd=analyse_get_url((char *)&(buf[dat_p+4]));
OK:
dat_p=http200ok();
// ritorna status
if (cmd == 0) {
for (byte pin = 0; pin < 8; pin++) {
status[pin] = char(48+settings.pins[pin]);
}
dat_p=es.ES_fill_tcp_data(buf,dat_p,status);
}
// pins
else if (cmd == 1) {
// controlla pin
if ((pinvalue > 1) && (pinvalue < 10)) {
int val = atoi(kvalstrbuf);
#ifdef SERIAL_LOG
Serial.print("pin=");//prints value to serial
Serial.println(pinvalue); //prints value to serial
Serial.print("val=");//prints value to serial
Serial.println(val); //prints value to serial
#endif
// controlla se set validi
if (val == 0 || val == 1) {
// controlla se il valore del pin e' cambiato e lo salva in eeprom
#ifdef SET_EEPROM
if (!( (byte) settings.pins[pinvalue-2] == (byte) val)) {
settings.pins[pinvalue-2] = (byte) val;
#endif
#ifdef SERIAL_LOG
Serial.println("salvo impostazioni");
#endif
#ifdef SET_EEPROM
saveConfig();
}
#endif
digitalWrite(pinvalue, val); // set the LED
// prepara buffer risposta
setpin[2]=char(48+pinvalue);
setpin[6]=char(48+val);
dat_p=es.ES_fill_tcp_data(buf,dat_p,setpin);
}
else flag_err = true;
// val err
}
else flag_err = true;
// pin err
}
#ifdef SERIAL_LOG
Serial.println(status);
#endif
if (flag_err) dat_p=es.ES_fill_tcp_data_p(buf,dat_p,PSTR("err\r\n"));
SENDTCP:
es.ES_www_server_reply(buf,dat_p); // send data
}
}