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
Revision 0:53f05303850a, committed 2012-12-31
- 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
--- /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