La idea sorgeix de la pregunta com optimitzar el consum d'aigua del meu hort ? Aguilar de Segarra pertany al 'Bages Sec' i per tant l'aigua de rec és escassa ( de fet és aigua de l'aixeta a casa meva ). És important poder emmagatzemar l'aigua de pluja per aprofitar-la pel rec de l'hort i en el nostre cas ho fem, ara com ara, amb un dipòsit de 1.000 litres, tot i que amb la pluviometria anual i la superfície de teulades que tenim podríem emmagatzemar entre 20.000 i 30.000 litres d'aigua a l'any.

En qualsevol cas és important no malgastar aquesta aigua i optimitzar-ne l'ús. Com ? Dons regant quan sigui necessari i això no és fàcil i menys per a uns pagesos aficionats com nosaltres. Les necessitats de rec d'un hort tenen moltes variables entre elles algunes d'homogènies per a tot l'hort com el tipus de terreny, el clima, etc. I d'altres que poden variar dins l'hort, per exemple, el tipus de cultiu, el pendent del terreny, etc. Filant molt prim caldria establir un pla de rec específic per a cada cultiu i la seva ubicació dins l'hort però això seria nivell 'professional'.

Cal simplificar una mica l'abast del projecte, i assumeixo les següents suposicions com a punt de partida:

  • El terreny és pla ( bastant cert ), i amb un únic tipus de sòl ( ens ho creiem ). Penseu que l'hort deu tenir uns 200 metres quadrats d'extensió i no l'aprofitem tot.
  • Suposem que tots els cultius de l'hort tenen les mateixes necessitats d'aigua. Això és completament fals, però començar a considerar els tipus de cultius voldria dir complicar el projecte: un sensor per a cada cultiu, una vàlvula/bomba de rec per a cada cultiu, etc. El cost econòmic de la solució adoptada és força assequible, però no despreciable i per començar ja està bé, potser més endavant millorarem la solució arribant a un compromís: separant els cultius en grups segons les necessitats de rec, molt aigua, poca aigua, etc. Ja ho veurem.

Doncs amb aquestes hipòtesis la idea és la següent: crear una xarxa de sensors ( de moment només un !! ) per mesurar les necessitats de rec de l'hort i regar-lo si cal. Tot això de forma automàtica, es clar, i a més, per evitar començar a escampar fils elèctrics per l'hort utilitzar energia solar i transmissors de ràdio.

Com que tinc força experiència en el món de la gestió de projectes TIC ( IT en anglès… ) i al tenir un component tecnològic força important he aplicat la metodologia de treball del meu dia a dia, simplificant-la al màxim i adaptant-la convenientment. En definitiva, he dividit el projecte en vàries fases i definit clarament quines tasques comporta cadascuna de les fases. I després anar dedicant hores a cada tasca, intentant no fer-ne gaires alhora ( en alguns moments dues o tres ) i de mica en mica anar avançant. També ajuda força evitar 'tasques' complicades de bon principi (;-D), o sigui, simplificar-ho tot al màxim però que funcioni, i després de mica en mica anar-ho complicant tot a mesura que ens calguin més prestacions, s'ha de saber parar a temps. També cal evitar canviar les especificacions a mig fer, això només comporta embolicar-ho i endarrerir-ho tot, i a part segur que serà més car. Amb això vull dir que un cop hàgim definit el què volem, fem-ho i punt, que ja tindrem temps d'afegir més coses portser esteu ja pensant en la versió 2.0. I evidentment si veiem que el projecte és impossible, refem-lo i tornem a començar, els objectius han de ser realitzables...

A grans trets he dividit el projecte de la versió 1.0 en tres grans fases:

  • Creació d'un prototipus funcional de sensor de nivell d'aigua, amb transmissió de dades sense fils i alimentat per energia solar.
  • Creació d'una estació de control per a recollir les dades dels sensors i emmagatzemar-les en una base de dades. Finalment, he decidit deixar la part d'automatització del rec per a més endavant, vegeu la secció 'Versió 2.0' per més detalls.
  • Creació d'una aplicació web de visualització gràfica de la informació.

Com veureu aquestes fases no són realment independents perquè cal anar fent tasques de diferents fases, per exemple, per poder provar un sensor: cal tenir un lloc per guardar les dades, no ? Per això en alguns moments es fan tasques de diferents fases alhora.

El que vull destacar sobretot és que al final les fases, tasques i tota la pesca es poden resumir en fulls de càlcul, que vaig mantenint quan puc, i es tracta d'anar marcant creuetes sobre les accions realitzades. Quan totes estan marcades, projecte acabat !!

Cal dir que ara com ara només he construit el sensor, estic emmagatzemant la informació en una base de dades i he fet una aplicació web, maslestorres.cat, per a visualitzar les dades. Falta fer la part d'automatització del rec.

O sigui:

Fase 1: 100%
Fase 2: 100%
Fase 3: 100%

La veritat és que pensava que seria molt més difícil però en aproximadament 3 mesos, i dedicant estones mortes, he aconseguit fer el prototipus de sensor solar i sense fils. Més endavant aniré detallant per parts cada component i la solució adoptada. Altra vegada, gràcies a internet, he aprofitat molta feina de persones amb similars inquietuds tot i que no he trobat cap exemple complet com el que jo proposo. En definitiva es pot considerar aquest projecte com la integració de molts altres projectes compartits a internet. Vull destacar aquí les principals fonts d'informació que he utilitzat:

Destaco també el llibre d'en Rob Faludi 'Building wireless sensor networks' (ISBN 978-0-596-80773-3), que ha estat molt important per engegar-ho tot plegat. Conté molts exemples senzills i útils que m'han ajudat a avançar molta feina.

Per decidir quan regar el meu hort m'he centrat en una magnitud física que és el volum d'aigua contingut al sòl ( VWC, de l'anglès 'Volumetric Water Content', en % per m3 ). Aquest valor es pot mesurar amb els sensors adequats, però la mare dels ous és saber com interpretar les lectures i és aquí on no he trobat massa ajuda. Jo puc saber quanta aigua per metre cúbic de sòl hi ha al meu hort però cal saber valorar si és suficient o no, i si cal obrir l'aixeta. Hi ha força documents a internet ( gràcies Sant Google !! ) que expliquen els paràmetres d'interès relacionats amb el rec com la capacitat de camp, el punt de pansiment ( traducció de l'autor: 'punto de marchitez permanente'), etc. Un bon exemple l'he trobat en un document, en castellà, de la Universitat de Texas A&M 'Uso de sensores de humedad del suelo para eficientizar el riego' dels autors Juan M. Enciso, Dana Porter i Xavier Périès. El recomano a tothom perquè realment tanca tot el cicle, és senzill de llegir i fins i tot hi ha algunes dades de les necessitats de rec segons el tipus de cultiu, això sí les unitats de mesura són imperials i per tant cal tenir la calculadora a mà. Tot i això és freqüent treballar amb percentatges pel que fa als valors del VWC.

En definitiva no hi ha una taula de dades que ens digui coses com: si tens tomàquets a l'hort i la quantitat d'aigua (VWC) està per sota del valor x cal regar, si és enciam… Així doncs aquesta taula l'haurem de fer jugant amb l'experiència, anar mesurant valors i anar regant i valorant si un cultiu funciona bé amb aquests paràmetres o no. No cal dir que si algú té aquesta feina feta i la vol compartir serà un bon punt de partida, però sense perdre de vista que segurament l'haurem d'adaptar a les condiciones del nostre hort.

Dit això he provat dues menes de sensors: DIY ( de l'anglès 'Do it yourself', o sigui que te'l fas tu mateix i que he batejat com model Kutrex1 ;-D ) i comercial, model Decagon EC-5. Els dos funcionen i segurament pel què han de fer a casa meva tots dos són bons.

El Kutrex1 és el model de dos claus típic que es troba en els blogs que he comentat abans, que es basa en mesurar la resistència entre els dos claus un cop enterrat: a més humitat menys resistència. Cada sensor serà diferent: tipus de clau, distància entre claus, aïllament i cal ser un manetes per fer-lo bé, sobretot ha d'estar molt ben aïllat. Això vol dir que s'haurà de calibrar cada sensor concret i no és fàcil, a més quan l'enterrem a l'hort les mesures canviaran a mesura que es rovelli i per tant tindrà data de caducitat. També complica l'electrònica, perquè caldrà posar algun transistor al circuit per alimentar-lo i augmentarà el consum de corrent del conjunt, cosa que pot suposar un problema si anem amb alimentació solar. Això sí, cost inferior a 1€ si voleu i la gent els fa servir.




El Decagon EC-5 és un sensor analògic basat en la mesura de la constant dièlectrica del sòl. És un circuit electrònic capaç de donar-nos un voltatge proporcional al VWC del terreny amb un petit marge d'error. El fabricant proporciona les funcions per realitzar la conversió voltatge-VWC. És el component més car del projecte però simplifica força les coses. Una alternativa força més barata pot ser el sensor VH400 de Vegetronix, que no he provat, també analògic, tot i que en la meva implementació requeriria circuiteria adicional per a funcionar correctament degut als requeriments de voltatge que té.




Més informació sobre el Decagon EC-5 la podeu trobar a la pàgina del fabricant.

Si voleu fer una xarxa low-cost de múltiples sensors ( vegeu l'apartat versió 2.0 ) es pot escollir el Kutrex1 per a tots els sensors i disposar d'un sensor comercial només per calibrar-los. És una idea per si no teniu gaire pressupost.

Com que volia un sensor sense fils vaig haver de trobar algún dispositiu capaç de llegir les dades que genera el sensor i enviar-les a alguna banda. Wi-Fi ? És una opció però resulta que hi ha un estàndard anomenat ZigBee molt més adeqüat per aquest projecte, vegeu-ne la definició ( traducció de l'autor, de la pàgina web ):

ZigBee és la única tecnologia sense fils basada en estàndards dissenyada per resoldre la necessitat de baixos costs, baix consum per a xarxes de sensors sense fils i control, per a qualsevol mercat.

Jo he escollit els dispositius ZigBee de la marca XBee que són fàcils de trobar i utilitzar, amb preus raonables ( entre 20€ i 100€, en funció de prestacions ). A la foto un XBee Pro amb antena, acompanyat d'un XBee Explorer USB ( més endavant sabreu per a que serveix ).




Entre moltes altres coses els XBee's del projecte són capaços de fer el següent:

  • Convertir una senyal analògica en digital, amb un conversor A/D de 10 bits. La senyal analògica ha d'estar entre 0 i 1,2 Volts, que curiosament quadra amb la sortida del sensor EC-5. I a més l'envia per ràdio automàticament.
  • Es pot programar un cicle de 'son'. Jo desperto el XBee durant 10 segons cada hora, suficient per tenir cinc lectures del sensor i enviar-les a l'ordinador. Això garanteix una gran autonomia del conjunt, penseu que funciona sense piles. Cal que el XBee utilitzi un firmware 'End Device AT', consultar el manual que trobareu a la web del fabricant.
  • Funciona amb només 3,3Volts d'alimentació.
  • El model que he escollit, sèrie Pro, té un abast de fins a 5km en camp obert, amb una potència de transmissió de 50mW. Per a horts més grans… però a mi em permet tenir el receptor dins de casa i guardar les dades en un dels ordinadors familiars. Els models més barats tenen menys cobertura, 120m en camp obert, però també consumeixen menys ( 2mW de potència de transmissió ).
  • Fer una xarxa amb aquests dispositius és senzill i amb moltes possibilitats, i amb la major part de la configuració automàtica. De fet, de tots els paràmetres que he remenat als XBees només n'hi ha tres relacionats amb la configuració de xarxa: nom de la xarxa i del node i l'adreça de la destinació. La resta són paràmetres per regular el cicle de son o el mostreig de les dades.

Tenim doncs el sensor i la ràdio, com els connectem ? Molt fàcil, connectar la sortida del sensor a l'entrada del XBee, jo he escollit l'entrada AD0, però el XBee en té quatre, o sigui que hi podriem penjar fins a 4 sensors per ràdio. Pot ser interessant combinar sensors VWC amb sensors de temperatura, humitat ambient, etc. D'altra banda el sensor necessita alimentació per poder generar dades, el fabricant recomana un voltatge entre 2,5Volts i 3,6Volts de corrent continu per l'EC-5, fixeu-vos que el XBee funciona amb 3,3Volts, i a més té un pin anomenat ON ( nº 13 ) que proporciona 3,3Volts quan està despert i 0Volts quan dorm, perfecte per alimentar el sensor, que també dormirà com el XBee i no malgastarà energia. El millor de tot és que no ha calgut fer absolutament cap adaptació a nivell d'electrónica per interconnectar-los.




Però qui alimenta el XBee ? Aquí, després de regirar per totes les botigues d'electrònica d'internet he trobat el circuit perfecte: Adafruit 390 Podem endollar-lo a un port USB, a una font d'alimentació de 5-6Volts DC o a un panell solar i càrrega una bateria al mateix temps que dóna de menjar al XBee. Només 25$ USA, això sí, paciència perquè sempre està esgotat, jo vaig tardar un mes a tenir-lo. Com que el sensor viu a l'hort, la font d'energia és el panell solar, i un cop carregada la bateria aguanta perfectament tota la nit la càrrega del XBee+sensor. Cal substituir una resistència del 390 per un sensor de temperatura, sobretot si ha de funcionar a l'exterior perquè la bateria utilitzada, tipus Li-Poly, només es pot carregar dins un marge de temperatures ( 0º - 50ºC ), millor que no s'encengui res, oi ? No patiu que si us decidiu pel 390, a la web d'Adafruit està molt ben explicat tot el què cal fer, pas a pas.

Aquí però dir que la única imperfecció del 390 és que el voltatge de sortida no quadra amb els 3,3Volts que calen per al XBee, per tant cal treure el soldador i posar un regulador de voltatge ( LD1117V33 ) amb els corresponents condensadors electrolítics, així de passada també estabilitzem encara més el corrent elèctric.

També he afegit un polsador per reiniciar el XBee, que només curtcircuita el pin RESET ( nº 5 ) a GND o terra ( nº 10 ). Això sembla una tonteria però és molt pràctic si treballem amb cicles de 'son' per despertar el XBee quan ens convingui i a més ja que tenim el soldador calent, dos filets més no són feina ;-D.

Resumint, els principals components d'aquest prototipus són:

  • Decagon EC-5
  • XBee Pro S2
  • 2 DBI 2,4 GHZ SMAM-RP ANTENNA
  • LD1117V33
  • Adafruit 390 ( USB / DC / Solar Lithium Ion/Polymer charger )
  • 10K Precision Epoxy Thermistor - 3950 NTC
  • Lithium Ion Polymer Battery - 3.7v 2600mAh
  • Medium 6V 2W Solar panel

Caldria afegir cables, condensadors electrolítics, un mini-jack estéreo, manguera termoretràctil per allargar el cable del panell solar, un proto-board, un tester, soldador, etc. però això jo ja ho tenia de quan estudiava… Això val uns 170€ ( sense iva ) però la meitat se l'emporta el sensor tot solet. Que consti que com que em vaig quedar sense vacances al 2012 em vaig permetre la inversió. Vull refinar el disseny per rebaixar-ne el preu i aquí les idees també seran benvingudes.




Els proto-boards són genials per a fer proves i més proves però sempre s'acaben desconnectant fils, els components també salten i vaja no crec que deixar-ho com a definitiu sigui una bona idea. Vaig comprar una placa de forats i amb el soldador i cable ben fi, ho vaig deixar més definitiu, si se'n pot dir així. Això sí que ho vull millorar que no ha queda prou elegant !!




Tot i això el XBee no està soldat a la placa, si no que vaig trobar adaptadors ( alerta que les potes dels XBee no tenen la separació estàndard dels circuits integrats de 2,54mm, si no que estan a 2mm !! ). Penseu que el XBee s'ha de programar via ordinador, a escollir el programa X-CTU del fabricant ( només Windows ) o un terminal per enviar comandes AT via port sèrie, tot i que per actualitzar el firmware o segons quin mode de funcionament feu servir només us valdrà el X-CTU. O sigui que durant les proves el vas posant i traient molts cops per canviar paràmetres ( jo he utilitzat el XBee Explorer USB de Sparkfun ). Pels que vulgueu provar-ho, aquí us deixo la parametrització del XBee del sensor que tinc en funcionament, els detalls de cada paràmetre al manual del fabricant ( Product Manual: XBee / XBee-PRO ZB RF Modules ):


ID 2012
DH 0
DL 0
NI EDEV1
IR 0x07D0
BD 7
SM 4
SP 0x7D0
SN 0x5A
ST 0x2710
SO 4
D0 2 
WH 20
		  

Finalment, cal construir el suport per a l'hort i posar els circuits dins una caixa preparada. Una fusta pintada, un tros de ferro corrugat, filferro per aguantar la placa solar, una caixa elèctrica estàndard Legrand ( de 3€!! ) i quatre brides per aguantar la caixa. He fixat els circuits a la caixa comprant una placa de baquelita que he tallat a mida i amb separadors de mètric 3 ho he cargolat tot.










Ja tenim el sensor instal·lat a l'hort i funcionant, però on va a parar tota aquesta informació ? Aquí ho he basat tot amb un microcontrolador de codi obert, l'Arduino, tot un descobriment. En concret un Arduino UNO, de 8 bits i 32KB de memòria, més que de sobres pel projecte en versió 1.0. Evidentment cal que l'Arduino tingui una ràdio per rebre les dades del sensor, per tant caldrà buscar la forma d'adaptar-hi un XBee i això ho podem fer mitjançant un circuit intermedi. N'hi ha molts al mercat i jo he utilitzat un 'Communication shield' de la marca libelium.




En aquest cas, i seguint el llibre d'en Rob Faludi, he programat el XBee amb un firmware 'Coordinator API' això vol dir que només podrem canviar paràmetres de configuració amb el programa X-CTU ( amb el Mac el podreu executar instal·lant Wine o via màquina virtual, VirtualBox, per exemple ). No cal que aquest XBee 'dormi' perquè la seva ubicació dins de casa ho facilita tot i de fet amb aquest firmware de coordinador no es podrà configurar. A més si tenim múltiples sensors a la xarxa el necessitem sempre despert. Destaco els següents paràmetres per a poder connectar amb el XBee del sensor:


ID 2012
DH 0
DL 0
CH 14
AP 2
NI COORDINATOR
BD 7
		  

L'Arduino envia la informació rebuda del sensor a un ordinador via port sèrie ( USB ) i allà un programa, arduinoToSQLite, guarda la informació en una base de dades.




El codi del sketch de l'Arduino és força senzill i bàsicament només processa les dades rebudes d'un paquet XBee tipus 'IO Data Sample' ( 0x92 ), que pot contenir dades de fins a quatre sensors, analògiques o digitals i les digitals les ignoro. Fet a partir del codi d'exemple de la web dels Arduino i les rutines de formateig vénen del projecte Desert Home. Dóno un format de paquet bastant simple, amb un delimitador inicial '#', separo els valors amb comes ',' i finalitzo el paquet amb un punt i coma ';' d'aquesta forma és possible enviar-lo a l'ordinador i processar-lo de forma més fàcil.

					
 /**
 * Copyright (c) 2012 Joan B. Altadill
 * Lectura de mostres analogiques via XBee
 *
 * Es formateja la informacio per a poder arribar via port serie a
 * un Mac, que la guardara en una bbdd SQLite: 
 * 
 * Header "#" + ZigBee IO Sample
 *
 **/

#include 

unsigned long svalue;

XBee xbee = XBee();
ZBRxIoSampleResponse ioSample = ZBRxIoSampleResponse();

void setup() { 
  Serial.begin(9600);
  xbee.setSerial(Serial);
}

// uint16_t 	getPacketLength ()
// void 	getZBRxIoSampleResponse (XBeeResponse &response)
// uint8_t 	getFrameDataLength ()
// uint8_t * 	getFrameData ()
// uint16_t 	getAnalog (uint8_t pin)

void loop() {
  //attempt to read a packet    
  xbee.readPacket();

  if (xbee.getResponse().isAvailable()) {
    // got something

    if (xbee.getResponse().getApiId() == ZB_IO_SAMPLE_RESPONSE) {
      xbee.getResponse().getZBRxIoSampleResponse(ioSample); 

      // Si s'ha llegit un paquet tipus IO sample envio a l'arduino un paquet 
      // via port serie amb el seguent format:
      // 64-bit Source address (8-bit), 
      // Per a cada port analogic actiu, el nº de port + valor llegit
      // finalment el delimitador.
      
      //64-bit address
      XBeeAddress64 senderLongAddress = ioSample.getRemoteAddress64();
      Serial.print("#");
      print32Bits(senderLongAddress.getMsb());
      print32Bits(senderLongAddress.getLsb());
      Serial.print(",");
      //Serial.print(senderLongAddress.getMsb());  
      //Serial.print(senderLongAddress.getLsb());  
        
      //for (int i = 0; i < xbee.getResponse().getFrameDataLength(); i++) {
      //  Serial.print(xbee.getResponse().getFrameData()[i], HEX);
      //}
      
      // Now, we have to deal with the data pins on the
      // remote XBee
        if (ioSample.containsAnalog()) {
          // the bitmask shows which XBee pins are returning
          // analog data (see XBee documentation for description)
            uint8_t bitmask = ioSample.getAnalogMask();
            for (uint8_t x = 0; x < 8; x++) {
              if ((bitmask & (1 << x)) != 0) {
                print8Bits(x);
                //Serial.print(x, HEX);
                Serial.print(",");
                //Serial.print(ioSample.getAnalog(x));
                print16Bits(ioSample.getAnalog(x));
                Serial.print(",");
              }
            }
        }    
    }   Serial.print(";");
  
  } else if (xbee.getResponse().isError()) {
    Serial.println(xbee.getResponse().getErrorCode());
  }
}

// these routines are just to print the data with
// leading zeros and allow formatting such that it
// will be easy to read.
void print32Bits(uint32_t dw){
  print16Bits(dw >> 16);
  print16Bits(dw & 0xFFFF);
}

void print16Bits(uint16_t w){
  print8Bits(w >> 8);
  print8Bits(w & 0x00FF);
}

void print8Bits(byte c){
  uint8_t nibble = (c >> 4);
  if (nibble <= 9)
    Serial.write(nibble + 0x30);
  else
    Serial.write(nibble + 0x37);
      
  nibble = (uint8_t) (c & 0x0F);
  if (nibble <= 9)
    Serial.write(nibble + 0x30);
  else
    Serial.write(nibble + 0x37);
}
		  

Ara cal fer un desenvolupament sobre l'ordinador per recollir la informació rebuda pel port sèrie. A casa tenim Macs, i tenim un petit Mac Mini ideal per a aquest projecte. Així doncs prenent com a base un codi exemple de la web d'Arduino he modificat el programa per tal de poder acabar gravant les dades en una base de dades, utilitzant l'entorn de desenvolupament d'Apple, el XCode, que ara com ara és gratuït. Fixeu-vos que un avantatge del MacOSX 10.8 ( Mountain Lion ) és que hi ha instal·lat de sèrie un SQLite v3, per tant només ha calgut crear la base de dades, les taules i directament gravar-hi les dades via SQL. El llenguatge utilitzat ha estat Objective-C per tota la interfície gràfica, però mantenint en C el codi pel port sèrie ( IOKit framework ). No posaré el codi de l'aplicació perquè són uns quants fitxers i algun més llarg del compte, només dir que l'única dificultat ha estat programar la recomposició dels paquets rebuts pel port sèrie i que envia l'Arduino, perquè la comunicació està basada en buffers, que poden contenir trossos de paquet, molts paquets, etc. Per tant cal reconstruir-los i d'aquí el format utilitzat, un paquet exemple podria ser:

#0013A2004090C5FA,00,0133,;
  • # - inici del paquet
  • 0013A2004090C5FA - adreça de 64-bits del XBee
  • , - separador
  • 00 - canal analògic AD0 del XBee ( el paquet podria contenir dades de fins a quatre canals )
  • , - separador
  • 0133 - valor mesurat a l'entrada AD0 del XBee, per tant és la lectura del sensor. És un número hexadecimal, 0x0133, que representa un voltatge en mVolts. El valor s'ha de corregir al programa doncs el XBee el mostreja amb 10 bits ( 2e10 = 1024 ) i el voltatge màxim que llegeix és 1,2 Volts. Per tant hi ha d'haver una línia al codi com aquesta per tenir el valor real llegit pel XBee:
  • mV0 = wvalue0 * 1200 / 1024;
  • , - separador
  • ; - final del paquet

Els separadors són útils per descomposar el paquet a l'hora de gravar-lo a la base de dades. De fet el paquet és un string, classe NSString, i utilizo un mètode d'aquesta classe per descomposar-lo en un array de strings separades per coma. La línia interessant seria:

NSArray *packet=[string componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@","]];

Imagino que altres programadors haurien escollit altres llenguatges, i segurament en altres entorns hi ha opcions molt més senzilles. Probablemet reconsideri aquesta opció més endavant.

Primer de tot agrair a l'Albert Fortes la paciència que ha tingut amb mi i dir també que el disseny de l'aplicació i l'elecció dels components necessaris per explotar les dades del sensor l'ha fet gairebé tota ell. Ha escollit els components adequats per implementar una pàgina web, accessible des d'Internet, tenint en compte els següents requeriments: codi obert, multiplataforma i maximitzar la simplicitat del conjunt ( tot i que això ja ho dono per impossible :-D ). Al final acaben apareixent noms ben extranys als que m'he hagut d'acostumar i m'ha tocat llegir molta més documentació tècnica. Us resumeixo les paraules clau que s'han implementat: cherrypy, python, json, jquery, HTML5, css, javascript, bootstrap, d3 i segur que n'oblido alguna. Maco ?

Resumint, he dividit en dues parts l'aplicació web que permet consultar les dades del sensor:

  • Al servidor que hostatja la base de dades, el Mac mini, he instal·lat un servidor HTTP que publica un servei web que permet consultar la base de dades, prenent com a paràmetres un interval de dates.
  • A les pàgines web que donen contingut al maslestorres.cat he creat la pàgina jardiNetVWC que consumeix el servei web del punt anterior i converteixen les dades en una gràfica. Aquestes pàgines estan allotjades a les infraestructures d'un proveïdor de servei d'Internet (ISP).

Del Mac mini, primer de tot dir que el MacOSX 10.8.2 ja porta una instal·lació de python plenament operativa, així que aquest component ja no cal instal·lar-lo:


[joanba:~] joanba% python
Python 2.7.2 (default, Jun 20 2012, 16:23:33) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
		  

Llavors hi he instal·lat cherrypy, que és un web framework basat en python. Això facilita molt la creació d'un servidor web per a publicar les dades del sensor. De fet el codi necessari no arriba a 100 línies. També afegir que el format escollit per publicar les dades ha estat json.


"""
MasLesTorres v0.1
20130121
"""

import cherrypy
import os.path
import json
import sqlite3 as sqlite
import logging
import logging.handlers

webserviceconf = os.path.join(os.path.dirname(__file__), 'maslestorres.conf')
dbname = "db/hort.db"

#Log config.
log = cherrypy.log

# Remove the default FileHandlers if present.
log.error_file = ""
log.access_file = ""

maxBytes = getattr(log, "rot_maxBytes", 10000000)
backupCount = getattr(log, "rot_backupCount", 3)

# Make a new RotatingFileHandler for the error log.
fname = getattr(log, "rot_error_file", "logs/error.log")
h = logging.handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount)
h.setLevel(logging.DEBUG)
#h.setFormatter(_cplogging.logfmt)
log.error_log.addHandler(h)

# Make a new RotatingFileHandler for the access log.
fname = getattr(log, "rot_access_file", "logs/access.log")
h = logging.handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount)
h.setLevel(logging.DEBUG)
#h.setFormatter(_cplogging.logfmt)
log.access_log.addHandler(h)

class WebService:
    
    def index(self):
        #raise cherrypy.HTTPRedirect("/html/index.html")
        return ""
    index.exposed = True

    def ExecuteSqlLiteQuery(self,Query):
        con=sqlite.connect(dbname)
        cur = con.cursor()
        cur.execute(Query)
        data = cur.fetchall()
        con.close()
        return data
    
    def ExecuteSqlLiteQueryOneRow(self,Query):
        con=sqlite.connect(dbname)
        cur = con.cursor()
        cur.execute(Query)
        data = cur.fetchone()
        con.close()
        return data

    #Per simplicitat adapto el codi a la infraestructura actual: 1 radio, 1 sensor
    #def SQLQuery(self,date1,date2,radio,channel):
    def SQLQuery(self,date1,date2):
        
        cherrypy.response.headers['Content-Type'] = "*"
        #cherrypy.response.headers['Access-Control-Allow-Headers'] = "*"
        cherrypy.response.headers['Access-Control-Allow-Methods'] = "POST, GET, OPTIONS"

        cherrypy.response.headers['Access-Control-Allow-Origin'] = "*"

        #sqlq    = "select count(*) from sensor_data" + " where time >= '" + date1 + "' and " + " time <= '" + date2 + "'"
        #counter = self.ExecuteSqlLiteQueryOneRow(sqlq)
        
        #Per simplicitat adapto el codi a la infraestructura actual: 1 radio, 1 sensor
        channel = 1
        radio   = "0013A2004090C5FA"
        
        if channel == 1:
            select = "select time, sample0 "
        elif channel == 2:
            select = "select time, sample1 "
        elif channel == 3:
            select = "select time, sample2 "
        elif channel == 4:
            select = "select time, sample3 "
        else:
            select = "select * "
        sqlq    = select + "from sensor_data" + " where time >= '" + date1 + "' and time <= '" + date2 + "' and radio_sn = '" + radio + "'"
        #print sqlq
        data    = self.ExecuteSqlLiteQuery(sqlq)
        #print data
        #counter = len(data)
        #data.insert(0,counter)
        result=[]
        for temps, mVolts in data:
            # data must be correctly parsed for jqPlot/d3: 20130210012300 --> "2013-02-10 01:23:00"
            temps_jqPlot = temps[:4] + "-" + temps[4:6] + "-" + temps[6:8] + " " + temps[8:10] + ":" + temps[10:12] + ":" + temps[12:14]
            # converteixo els mVolts llegits al XBee en VWC%, amb formula Decagon:
            # VWC (m3/m3) = 0.00133 * mV - 0.456, x100 per obtenir %
            VWC  = (0.00133 * mVolts - 0.456) * 100
            punt = [temps_jqPlot, "%.2f" % VWC]
            result.append(punt)
        return json.dumps(result)
    SQLQuery.exposed = True

if __name__ == "__main__":
    # CherryPy always starts with app.root when trying to map request URIs
    # to objects, so we need to mount a request handler root. A request
    # to '/' will be mapped to HelloWorld().index().
    cherrypy.quickstart(WebService(), config=webserviceconf)
    #else:
    # This branch is for the test suite; you can ignore it.
    #cherrypy.tree.mount(WebService(), config=webserviceconf)


		  

El fitxer de configuració que cherrypy necessita és ben senzill:


[global]
server.socket_host = "0.0.0.0"
server.socket_port = 8080
server.thread_pool = 10

log.screen: False

[/]
tools.staticdir.root: '/Users/joanba/Desktop/Arduino/maslestorres.cat/'

[/html]
tools.staticdir.on: True
tools.staticdir.dir: 'html'

		  

La web maslestorres.cat és la part que m'ha ocupat més temps, perquè d'entrada no tinc gaires habilitats amb del disseny i també perquè és la primera web amb cara i ulls que he fet. O sigui, que vaig perdre unes quantes nits buscant els templates per a la creació de pàgines web i després de remenar i provar-ne uns quants em vaig decidir per un dels més utilitzats, Twitter Bootstrap . No l'he modificat pràcticament gens, ja el trobo prou maco…

Arribats en aquest punt, cal cridar el servei web i representar de forma gràfica les dades, o sigui, javascript, jquery i d3. Tots aquests components s'executen al vostre navegador, per tant, en teniu disponible tot el codi font.

La llibreria gràfica d3 és realment molt potent i permet realitzar uns gràfics espectaculars. Cal dir que la complexitat és gran i costa començar a treure-li partit, tot i que hi ha molts exemples disponibles. L'he utilitzat en dues pàgines: jardiNetVWC, on hi ha un gràfic senzill amb una única línia, però que permet fer zoom i també a la pàgina personal, Joan, on he intentat definir els meus interessos amb un gràfic.

Finalment destacar que les eines utilitzades en aquest desenvolupament han estat XCode per a la part python i Aptana per la resta. Ambdues són gratuïtes.

Després d'unes setmanes amb el prototipus funcionant començo a veure dades que crec que poden ser significatives. D'entrada, durant aquest hivern i després d'unes setmanes sense pluja ni rec, el VWC oscil·la al voltant del 12% ( vegeu les dades de Febrer 2013 a la gràfica ), al regar l'hort el 03/03/2013, amb uns 1.000 litres d'aigua via gota a gota, el VWC assoleix un pic del 36% i llavors comencen les pluges, a partir del 05/03/2013, i continuades durant 72 hores, i havent recollit 70litres/m2, assoleixo un pic de VWC del 44%. Tots aquests pics baixen de seguida que la pluja s'atura o es redueix en intensitat, per tant, sospito que deuen ser un bon indicador de la capacitat de camp del sòl ( el punt a partir del qual el terreny no pot absorvir més aigua i per tant es formen bassals ). Consultant la documentació que he esmentat abans veig que per a terrenys argilosos la capacitat de camp es situa en valors del 40%, cosa que s'adiu bastant amb el terreny del meu hort.

Aniré ampliant aquesta secció a mesura que pugui interpretar les dades que vaig recollint. Ara ja començaré aviat a treballar l'hort i per tant a cultivar i serà moment de tenir dades més interessants. Tot arribarà.

El projecte versió 1.0 ja està ben definit i tinc clar fins on fer-lo arribar, de fet ja està gairebé enllestit doncs només estic resolent els errors del codi que van apareixent. A més he anat ruminat bastant com millorar parts del projecte i han anat sorgint algunes idees. Us les explico una mica.

M'agradaria integrar tots els components del sensor en un únic circuit. L'Adafruit 390 és un circuit molt versàtil per a molts projectes però per aquest en concret m'agradaria modificar-lo per donar 3,3Volts a la sortida, sense haver de regular-la i a més disposar dels sockets per integrar el XBee directament i ja posats a demanar deixar espai lliure per poder integrar-hi altres components com els sensors. Els esquemes i plànols del circuit estan disponibles al github i són el millor punt de partida però desconec les implicacions legals d'aprofitar-ho.

Rebaixar-ne el cost. Un prototipus com aquest està bé com a hobby però no té cap possibilitat comercial. Caldria refinar la validesa del sensor perquè és amb diferència el component més car, potser buscant altres mètodes més barats. La idea d'aquest projecte és crear un model de xarxa de sensors, i no només un sensor per a un hortet. Imagineu que volem regar una finca de vàries hectàrees amb diferents cultius o amb una orografia complicada, hi haurà zones amb diferents necessitats de rec i per tant haurem d'instal·lar almenys un sensor en cada zona. Seria convenient fixar un preu límit del conjunt i veure quines evolucions es poden fer per aconseguir-lo, també seria interessant saber si hi ha més gent interessada en aquest component, fabricar-ne molts també redueix el cost. Què us sembla 50€ ? Es pot aconseguir ?

Autonomia per a l'Arduino i evitar la dependència del servidor… M'agradaria passar la intel·ligència del projecte del Mac a l'Arduino i fer-lo més robust. Per exemple, si l'ordinador està apagat i la base de dades no funciona, l'Arduino ha de ser capaç de guardar les dades i actualitzar la base de dades quan torni a estar disponible. Per tant hi ha canvis importants a implementar i de fet ja he començat a treballar-hi.

  • Afegir un sistema de fitxers.
    Per exemple, utilitzant el 'Wireless SD Shield'. Aquest part ha estat senzilla, amb un parell d'hores he substituit el shield que hi havia i l'Arduino ja està gravant les dades recollides en una tarja microSD a més de continuar enviant les dades a l'aplicació arduinoToSQLite. De moment però sense guardar l'hora en que s'han recollit les dades, bé si que hi ha una crida a millis() i es guarda però no és util doncs tenim cap hora de referència. Ara l'hora de recollida de les dades l'està posant l'arduinoToSQLite al guardar les dades a la bbdd.
  • Afegir un rellotge (Real Time Clock).
    Aquest és el pas en procés, ara que reviso la pàgina, i he escollit un rellotge senzill i barat: Adafruit 264. Encara no el tinc però ja he instal·lat la RTClib a l'entorn de desenvolupament de l'Arduino... També canviaré l'Arduino UNO que he fet servir fins ara per un Arduino MEGA 2560.
  • Refer l'aplicació arduinoToSQLite.
    Aquest punt l'he rumiat bastant i penso que tot i que la funcionalitat ha de canviar poc o gens sí que cal refer l'aplicació en un entorn multiplataforma. Ara és totalment cautiu del Macs i a part el codi en Objective-C és massa enrevessat. He decidit portar el codi a python que és multiplataforma i per tant el podré continuar posant al Mac mini però també a molts altres llocs. També penso simplificar moltes coses: desapareixerà l'interfície gràfica i la substituiré per un fitxer de paràmetres, i instal·laré l'aplicació com un servei de la màquina, sense interacció amb l'usuari.
  • Afegir una pantalla amb teclat.
    A veure quan arribo en aquest punt !!! D'entrada només funcionalitats bàsiques: consulta de la darrera lectura dels sensors, ajustar l'hora del rellotge, etc. Encara és una llista oberta...