/*
 Klient czujnika Pachube
 
 Szkic łączy czujnik analogowy z serwisem Pachube (obecnie Xively, xively.com)
 za pośrednictwem modułu sieciowego. Do budowy urządzenia można użyć modułu Arduino Ethernet lub
 modułu Adafruit Ethernet (oba moduły będą działały, pod warunkiem że
 dysponujemy modułem Wiznet Ethernet).
 
 Obwód:
 * Czujnik analogowy podłączony do pinu analogowego nr 0
 * Moduł sieciowy jest podłączony do pinów nr 10, 11, 12 i 13.
 
 data utworzenia: 15 marca 2010
 data modyfikacji: 4 września 2010
 autor: Tom Igoe
 
 http://www.tigoe.net/pcomp/code/category/arduinowiring/873
 Kod tego szkicu jest dostępny publicznie.
 */

#include <SPI.h>
#include <Ethernet.h>

// Wartości w tablicy należy zastąpić adresem MAC modułu sieciowego:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// Wartości w tablicy należy zastąpić adresem IP modułu sieciowego. Zapisany poniżej adres IP może działać w niektórych sieciach:
byte ip[] = { 
  192, 168, 1, 110 };

// Inicjalizuje bibliotekę modułu sieciowego:
EthernetClient client;

long lastConnectionTime = 0; // reprezentuje czas nawiązania ostatniego połączenia z serwerem (w milisekundach)
boolean lastConnected = false; // stan połączenia podczas ostatniego wykonywania głównej pętli
const int postingInterval = 10000; // opóźnienie pomiędzy kolejnymi aktualizacjami w serwisie Pachube.com

void setup() {
  // uruchamia połączenie sieciowe i port szeregowy:
  Ethernet.begin(mac, ip);
  Serial.begin(9600);

  // daje modułowi sieciowemu czas na uruchomienie:
  delay(1000);
}

void loop() {
  // odczytuje stan czujnika analogowego:
  int sensorReading = analogRead(A0); 

  // Jeśli otrzymano dane przychodzące za pośrednictwem połączenia sieciowego,
  // program przekazuje je do portu szeregowego. Wyświetlanie tych danych ma na celu wyłącznie
  // ułatwienie diagnozowania szkicu:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // Jeśli połączenie sieciowe nie jest dostępne, ale pętla została wykonana
  // należy zatrzymać klienta:
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }

  // Jeśli połączenie sieciowe nie jest dostępne i jeśli minęło dziesięć sekund
  // od ostatniego połączenia, program ponownie nawiązuje połączenie i wysyła dane:
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    sendData(sensorReading);
  }
  // zapisuje stan połączenia dla następnej iteracji
  // pętli:
  lastConnected = client.connected();
}

// Ta metoda nawiązuje połączenie HTTP z serwerem:
void sendData(int thisData) {
  // Jeśli udało się nawiązać połączenie:
  if (client.connect("www.pachube.com", 80)) {
    Serial.println("connecting...");
    // wysyła żądanie PUT protokołu HTTP.
    // Tutaj należy wpisać adres używanego kanału:
    client.print("PUT /api/YOUR_FEED_HERE.csv HTTP/1.1\n");
    client.print("Host: www.pachube.com\n");
    // tutaj należy podać otrzymany klucz Pachube API:
    client.print("X-PachubeApiKey: TWÓJ_KLUCZ_API\n");
    client.print("Content-Length: ");


    // oblicza długość danych czujnika (w bajtach):
    int thisLength = getLength(thisData);
    client.println(thisLength, DEC);


    // ostatnie elementy żądania HTTP PUT:
    client.print("Content-Type: text/csv\n");
    client.println("Connection: close\n");


    // właściwa treść żądania PUT:
    client.println(thisData, DEC);


    // zapisuje czas nawiązania połączenia:
    lastConnectionTime = millis();
  }
  else {
    // jeśli nie można nawiązać połączenia:
    Serial.println("Nie można nawiązać połączenia.");
  }
}


// Ta metoda oblicza liczbę cyfr składających się na
// odczyt czujnika. Ponieważ każda cyfra jest znakiem ASCII
// reprezentowanym przez jeden bajt, liczba cyfr jest równa
// liczbie bajtów:

int getLength(int someValue) {
  // istnieje co najmniej jeden bajt:
  int digits = 1;
  // dzieli tę wartość przez 10,
  // dodając za każdym razem jedną cyfrę do licznika
  // aż do osiągnięcia wartości 0:
  int dividend = someValue /10;
  while (dividend > 0) {
    dividend = dividend /10;
    digits++;
  }
  // zwraca liczbę cyfr:
  return digits;
}

