yet another 18B20 Temperature sensor. variable number of sensors working in parasite mode, serial 16x2 display with diagnostic output and post to a rest web service

Dependencies:   EthernetInterface HTTPClient NTPClient mbed-rtos mbed

Files at this revision

API Documentation at this revision

Comitter:
wkinkeldei
Date:
Mon Dec 31 12:08:24 2012 +0000
Child:
1:9e88b2508768
Commit message:
first working version with all needed features implemented: measure, display, post

Changed in this revision

EthernetInterface.lib Show annotated file Show diff for this revision Revisions of this file
HTTPClient.lib Show annotated file Show diff for this revision Revisions of this file
NTPClient.lib Show annotated file Show diff for this revision Revisions of this file
collector_proxy.cpp Show annotated file Show diff for this revision Revisions of this file
collector_proxy.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
ntp_proxy.cpp Show annotated file Show diff for this revision Revisions of this file
ntp_proxy.h Show annotated file Show diff for this revision Revisions of this file
one_wire.cpp Show annotated file Show diff for this revision Revisions of this file
one_wire.h Show annotated file Show diff for this revision Revisions of this file
sensor.cpp Show annotated file Show diff for this revision Revisions of this file
sensor.h Show annotated file Show diff for this revision Revisions of this file
sparkfun.cpp Show annotated file Show diff for this revision Revisions of this file
sparkfun.h Show annotated file Show diff for this revision Revisions of this file
temperature_sensor.cpp Show annotated file Show diff for this revision Revisions of this file
temperature_sensor.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetInterface.lib	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/EthernetInterface/#a0ee3ae75cfa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPClient.lib	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/HTTPClient/#1f743885e7de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NTPClient.lib	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/NTPClient/#881559865a93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/collector_proxy.cpp	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,34 @@
+#include "collector_proxy.h"
+#include "HTTPClient.h"
+
+#include <cstring>
+
+CollectorProxy::CollectorProxy(char *url) :base_url(url) {
+}
+
+int CollectorProxy::send_measure(char *path_part, int value) {
+    HTTPClient http;
+    HTTPMap data;
+    char str[512];
+    HTTPText in_text(str, 512);
+    
+    char url[200];
+    strcpy(url, base_url);
+    strcat(url, "/");
+    strcat(url, path_part);
+
+    char value_buffer[10];
+    sprintf(value_buffer, "%d", value);
+    data.put("value", value_buffer);
+
+    int ret = http.post(url, data, &in_text);
+
+    if (!ret) {
+        // printf("Executed POST successfully - read %d characters\n", strlen(str));
+        // printf("Result: %s\n", str);
+        return 1;
+    } else {
+        // printf("Error - ret = %d - HTTP return code = %d\n", ret, http.getHTTPResponseCode());
+        return 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/collector_proxy.h	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,16 @@
+#ifndef COLLECTOR_PROXY_H
+#define COLLECTOR_PROXY_H
+
+#include "mbed.h"
+#include "HTTPClient.h"
+
+class CollectorProxy {
+public:
+    CollectorProxy(char *url);
+    int send_measure(char *path_part, int value); // result 1:OK, 0:fail
+
+private:
+    char *base_url;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,158 @@
+#include "mbed.h"
+#include "rtos.h"
+#include "EthernetInterface.h"
+
+#include <list>
+
+#include "sparkfun.h"
+#include "ntp_proxy.h"
+#include "collector_proxy.h"
+#include "sensor.h"
+#include "temperature_sensor.h"
+
+SparkFun display(p28);
+list<Sensor *> sensors;
+
+void wait_minutes(int m = 1) {
+    while (m-- > 0)
+        Thread::wait(1000 * 60);
+}
+
+void wait_seconds(int s = 1) {
+    while (s-- > 0)
+        Thread::wait(1000);
+}
+
+/*
+    ntp Thread: poll NTP Server every 3 hours
+*/
+void ntp_thread(void const *args) {
+    NtpProxy ntp;
+    
+    while (true) {
+        display.show_ntp_status('t');
+        if (ntp.set_time()) {
+            // successful: wait 3 hours
+            display.show_ntp_status('T');
+            wait_minutes(180);
+        } else {
+            // failure: retry after 5 minutes
+            display.show_ntp_status('?');
+            wait_minutes(5);
+        }
+    }
+}
+
+/*
+    display Thread: show a sensor every 2 seconds and current time
+*/
+void display_thread(void const *args) {
+    char buffer[20];
+    int last_minute = -1;
+    time_t seconds;
+    struct tm *t;
+    list<Sensor *>::iterator it = sensors.begin();
+    
+    while (true) {
+        // display next sensor's measure (if any)
+        if (it != sensors.end()) display.show_sensor_measure((*it)->get_name(), (*it)->last_measure());
+        it++;
+        if (it == sensors.end()) it = sensors.begin();
+        
+        // display time if minute is different from displayed value
+        seconds = time(NULL) + 3600; // FIXME: time-zone calculations wanted -- toggle switch?
+        t = localtime(&seconds);
+        if (last_minute != t->tm_min) {
+            last_minute = t->tm_min;
+            strftime(buffer, 20, "%H:%M", t);
+            display.show_time_text(buffer);
+        }
+
+        wait_seconds(2);
+    }
+}
+
+/*
+    measure Thread: read all sensors every 10 seconds
+*/
+void measure_thread(void const *args) {
+    while (true) {
+        list<Sensor *>::iterator it;
+        int nr = 0;
+        for (it = sensors.begin(); it != sensors.end(); it++) {
+            display.show_current_sensor((*it)->get_kind(), nr, '<');
+
+            (*it)->prepare_measure();
+            display.show_current_status('>');
+            (*it)->measure();
+            display.show_current_status('='); // oder '?' falls falsch
+
+            wait_seconds(1);
+
+            nr++;
+        }
+        display.clear_current_sensor();
+
+        wait_seconds(10); // FIXME: increase to 60 seconds
+    }
+}
+
+/*
+    send Thread: post measures to Statistics Collector every 15 minutes
+*/
+void send_thread(void const *args) {
+    CollectorProxy collector("http://kinkeldei-net.de:81/sensor");
+
+    while (true) {
+        // 10 minute delay with feedback in the last 9 minutes
+        for (int i=10; i>=0; i--) {
+            display.show_network_status(i > 9 ? ' ' : '0' + i);
+            wait_minutes(1);
+        }
+        
+        list<Sensor *>::iterator it;
+        for (it = sensors.begin(); it != sensors.end(); it++) {
+            display.show_network_status('P');
+            int ret = collector.send_measure((*it)->get_url_part(), (*it)->get_value());
+            
+            display.show_network_status(ret ? 'O' : 'E');
+            wait_seconds(2);
+        }
+    }
+}
+
+/*
+    main Thread: initialize and flash a LED
+*/
+int main() {
+    display.print_init_message();
+
+    // ConfigReader c('config.ini');
+    // c.read_config();
+    
+    sensors.push_back((Sensor *) new TemperatureSensor(p21, "erlangen/temperatur/demo", "demo"));
+
+    /*
+    sensors.push_back((Sensor *) new TemperatureSensor(p21, "trainmeusel/temperatur/heizung", "heizung"));
+    sensors.push_back((Sensor *) new TemperatureSensor(p22, "trainmeusel/temperatur/keller",  "keller"));
+    sensors.push_back((Sensor *) new TemperatureSensor(p23, "trainmeusel/temperatur/flur",    "flur"));
+    sensors.push_back((Sensor *) new TemperatureSensor(p24, "trainmeusel/temperatur/aussen",  "aussen"));
+    */
+    
+    // must come from configreader later, then remove:
+    EthernetInterface eth;
+    eth.init("192.168.2.175", "255.255.255.0", "192.168.2.1");
+    eth.connect();
+
+    Thread t1(ntp_thread);
+    Thread t2(display_thread);
+    Thread t3(measure_thread);
+    Thread t4(send_thread);
+
+    // a periodical flash should indicate "we are alive"
+    DigitalOut led(LED1);
+    while (true) {
+        led = !led;
+        wait_seconds(1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#88a1a9c26ae3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/49c296715c73
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ntp_proxy.cpp	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,10 @@
+#include "ntp_proxy.h"
+
+NtpProxy::NtpProxy(void) {
+    ntp_client = new NTPClient();
+}
+
+int NtpProxy::set_time(void) {
+    NTPResult r = ntp_client->setTime("time.apple.com");
+    return r == NTP_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ntp_proxy.h	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,16 @@
+#ifndef NTP_PROXY_H
+#define NTP_PROXY_H
+
+#include "mbed.h"
+#include "NTPClient.h"
+
+class NtpProxy {
+    NTPClient *ntp_client;
+
+public:
+    NtpProxy(void);
+    
+    int set_time(void);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/one_wire.cpp	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,114 @@
+#include "one_wire.h"
+
+/* "borrowed" from snatch59: OneWireCRC and simplified for my needs */
+ 
+const int timing[] = {6, 64, 60, 10, 9, 55, 0, 480, 70, 410};
+ 
+OneWire::OneWire(PinName pin) : port(pin) {
+}
+ 
+int OneWire::reset() {
+    int result = 0;    // sample presence pulse result
+        
+    wait_us(timing[6]);
+    port.output();
+    port = 0;
+    wait_us(timing[7]);
+    port.input();
+    wait_us(timing[8]);
+    result = !(port & 0x01);
+    wait_us(timing[9]);
+    
+    return result;
+}
+ 
+void OneWire::write_bit(int bit) {
+    bit = bit & 0x01;
+    
+    if (bit) {
+        // Write '1' bit
+        port.output();
+        port = 0;
+        wait_us(timing[0]);
+        port.input();
+        wait_us(timing[1]);
+    } else {
+        // Write '0' bit
+        port.output();
+        port = 0;
+        wait_us(timing[2]);
+        port.input();
+        wait_us(timing[3]);
+    }
+}
+ 
+int OneWire::read_bit() {
+    int result;
+    
+    port.output();
+    port = 0;
+    wait_us(timing[0]);
+    port.input();
+    wait_us(timing[4]);
+    result = port & 0x01;
+    wait_us(timing[5]);
+       
+    return result;
+}
+ 
+void OneWire::write_byte(int data) {
+    // Loop to write each bit in the byte, LS-bit first
+    for (int loop = 0; loop < 8; loop++) {
+        write_bit(data & 0x01);
+        
+        // shift the data byte for the next bit
+        data >>= 1;
+    }
+}
+ 
+int OneWire::read_byte() {
+    int result = 0;
+    
+    for (int loop = 0; loop < 8; loop++) {
+        // shift the result to get it ready for the next bit
+        result >>= 1;
+        
+        // if result is one, then set MS bit
+        if (read_bit()) result |= 0x80;
+    }
+    
+    return result;
+}
+ 
+void OneWire::block(char* data, int data_len) {
+    for (int loop = 0; loop < data_len; loop++) {
+        data[loop] = read_byte(); // original: touchByte(data[loop]);
+    }
+}
+
+void OneWire::prepare_read() {
+    reset();
+    write_byte(SKIP_ROM);
+    write_byte(CONVERT);
+
+    // switch on parasite power while waiting.
+    port.output();
+    port = 1;
+}
+
+int OneWire::read_temperature() {
+    char data[9];
+    short *raw_temp = (short *) data;
+    int temperature = -99;
+    
+    reset();
+    write_byte(SKIP_ROM);
+    write_byte(READSCRATCH);
+    block(data, 9);
+    
+    if (data[5] == 255 && data[7] == 16) {
+        temperature = *raw_temp >> 4;
+    }
+    
+    return temperature;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/one_wire.h	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,40 @@
+#ifndef _ONE_WIRE_H
+#define _ONE_WIRE_H
+
+#include "mbed.h"
+
+// One Wire command codes
+#define OVERDRIVE_SKIP    0x3C
+// ROM commands
+#define SEARCH_ROM        0xF0
+#define READ_ROM          0x33
+#define MATCH_ROM         0x55
+#define SKIP_ROM          0xCC
+#define ALARM_SEARCH      0xEC
+// Functions Commnds
+#define CONVERT           0x44
+#define WRITESCRATCH      0x4E
+#define READSCRATCH       0xBE
+#define COPYSCRATCH       0x48
+#define RECALLE2          0xB8
+#define READPOWERSUPPLY   0xB4
+
+class OneWire {
+private:
+    DigitalInOut port;
+
+public:
+    OneWire(PinName pin);
+    int reset();
+    void write_bit(int bit);
+    int read_bit();
+    void write_byte(int data);
+    int read_byte();
+    void block(char* data, int data_len);
+    
+    // high level functions: prepare(), delay(1000ms), read()
+    void prepare_read();
+    int read_temperature();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensor.cpp	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,41 @@
+#include "sensor.h"
+
+Sensor::Sensor(char kind, PinName pin, char *url_part, char *name) : kind(kind), pin(pin), url_part(url_part), name(name) {
+    cleanup_measure();
+}
+
+void Sensor::set_value(int v) {
+    value = v;
+}
+
+int Sensor::get_value(void) {
+    return value;
+}
+
+char Sensor:: get_kind(void) {
+    return kind;
+}
+
+int Sensor::get_pin(void) {
+    return pin;
+}
+
+char *Sensor::get_url_part(void) {
+    return url_part;
+}
+
+char *Sensor::get_name(void) {
+    return name;
+}
+
+void Sensor::prepare_measure(void) {}
+
+void Sensor::measure(void) {}
+
+void Sensor::cleanup_measure(void) {
+    value = 0;
+}
+
+char *Sensor::last_measure(void) {
+    return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sensor.h	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,32 @@
+#ifndef SENSOR_H
+#define SENSOR_H
+
+#include "mbed.h"
+
+class Sensor {
+public:
+    // T26: buero/temperatur    Buero
+    Sensor(char kind, PinName pin, char *url_part, char *name);
+    
+    void set_value(int v);
+    int get_value(void);
+    
+    char get_kind(void);
+    int get_pin(void);
+    char *get_url_part(void);
+    char *get_name(void);
+    
+    virtual void prepare_measure(void);
+    virtual void measure(void);
+    virtual void cleanup_measure(void);
+    virtual char *last_measure(void);
+    
+protected:
+    char kind;
+    PinName pin;
+    char *url_part;
+    char *name;
+    int value;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sparkfun.cpp	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,102 @@
+#include "sparkfun.h"
+#include "rtos.h"
+
+/*
+    1234567890ABCDEF
+   [Buero       52°C]
+   [T26> P N x 11:42]
+    ^  ^ ^ ^ ^   ^
+    |  | | | |   |
+    |  | | | |   |
+    |  | | | |   +-- 27: Uhrzeit "hh:mm" / Datum "Mar03" / Uptime "  42d"
+    |  | | | |
+    |  | | | +-- 25: Reserve
+    |  | | |
+    |  | | +-- 23: NTP Status: t=lesen, T=ok, ?=error
+    |  | |
+    |  | +-- 21: Netz: P)ost O)k E)rror [1-9] = in x Minuten gehts los
+    |  |
+    |  +-- 19: < senden, > lesen, = fertig, ? fehler
+    |
+    +-- 16: gerade/zuletzt gemessener Sensor
+
+*/
+
+SparkFun::SparkFun(PinName tx) : Serial(tx, NC) {
+    baud(9600);
+}
+
+void SparkFun::clear(void) {
+    control_sequence(0x01);
+}
+
+void SparkFun::set_cursor_position(int pos) {
+    if (pos >= 16) {
+        pos = 64 + pos - 16;
+    }
+    control_sequence(0x80 + pos);
+}
+
+void SparkFun::control_sequence(char c) {
+    putc(0xfe);
+    putc(c);
+}
+
+void SparkFun::print_init_message(void) {
+    clear();
+    
+    set_cursor_position(0);    
+    puts("TempSensor");
+    
+    // will get overridden very soon.
+    // set_cursor_position(16);
+    // puts("init");
+}
+
+void SparkFun::show_sensor_measure(char *name, char *measure) {
+    Thread::wait(50); // time for 48 characters.
+    set_cursor_position(0);
+    printf("%-12s%4s", name, measure);
+}
+
+void SparkFun::clear_current_sensor(void) {
+    Thread::wait(50); // time for 48 characters.
+    set_cursor_position(16);
+    puts("    ");
+}
+
+void SparkFun::show_current_sensor(char kind, int nr, char status) {
+    Thread::wait(50); // time for 48 characters.
+    set_cursor_position(16);
+    printf("%c%02d%c", kind, nr, status);
+}
+
+void SparkFun::show_current_status(char status) {
+    Thread::wait(50); // time for 48 characters.
+    set_cursor_position(19);
+    putc(status);
+}
+
+void SparkFun::show_network_status(char status) {
+    Thread::wait(50); // time for 48 characters.
+    set_cursor_position(21);
+    putc(status);
+}
+
+void SparkFun::show_ntp_status(char status) {
+    Thread::wait(50); // time for 48 characters.
+    set_cursor_position(23);
+    putc(status);
+}
+
+void SparkFun::show_spare_status(char status) {
+    Thread::wait(50); // time for 48 characters.
+    set_cursor_position(25);
+    putc(status);
+}
+
+void SparkFun::show_time_text(char *text) {
+    Thread::wait(50); // time for 48 characters.
+    set_cursor_position(27);
+    printf("%-5s", text);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sparkfun.h	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,27 @@
+#ifndef SPARKFUN_H
+#define SPARKFUN_H
+
+#include "mbed.h"
+
+class SparkFun : public Serial {
+public:
+    SparkFun(PinName tx);
+
+    // low level functions
+    void clear(void);
+    void set_cursor_position(int pos);
+    void control_sequence(char c);
+    
+    // high level functions
+    void print_init_message(void);
+    void show_sensor_measure(char *name, char *measure);
+    void clear_current_sensor(void);
+    void show_current_sensor(char kind, int nr, char status = ' ');
+    void show_current_status(char status);
+    void show_network_status(char status);
+    void show_ntp_status(char status);
+    void show_spare_status(char status);
+    void show_time_text(char *text);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/temperature_sensor.cpp	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,20 @@
+#include "temperature_sensor.h"
+#include "rtos.h"
+
+TemperatureSensor::TemperatureSensor(PinName pin, char *url_part, char *name) : Sensor('T', pin, url_part, name), one_wire(pin) {
+}
+
+void TemperatureSensor::prepare_measure(void) {
+    one_wire.prepare_read();
+    Thread::wait(1000);
+}
+
+void TemperatureSensor::measure(void) {
+    value = one_wire.read_temperature();
+}
+
+char *TemperatureSensor::last_measure(void) {
+    sprintf(buffer, "%d\337C", value);
+    
+    return buffer;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/temperature_sensor.h	Mon Dec 31 12:08:24 2012 +0000
@@ -0,0 +1,20 @@
+#ifndef TEMPERATURE_SENSOR_H
+#define TEMPERATURE_SENSOR_H
+
+#include "sensor.h"
+#include "one_wire.h"
+
+class TemperatureSensor : public Sensor {
+public:
+    TemperatureSensor(PinName pin, char *url_part, char *name);
+
+    virtual void prepare_measure(void);
+    virtual void measure(void);
+    virtual char *last_measure(void);
+
+protected:
+    OneWire one_wire;
+    char buffer[10];
+};
+
+#endif