User Tools

Site Tools


projects:home_monitor:home

Home monitor

~~META:description abstract=Set of uC powered devices to monitor the house~~ microcontroller sensor web http power

Set of uC powered devices to monitor the house, including :

  • Electrical power consumption
  • Water consumption
  • Temperature (inside/outside)

All compatible with collected datalogger.

Features

  • Electrical power measurement (main, heaters, water heater, server, box freezer, box main …)
  • Water consumption sensor
  • Inside and outside temperature monitor

Environment

The devices are to operate inside the home network, over TCP/IP protocol, HTTP was chosen for its easier debugging as well as its versatility.

The datalogger server is to fetch the data by itself, eg the sensors just have to implement a web server.

The sensors will expose data as plain ascii text.

Sensing

Power

Measuring power deals with measuring current as well as peak voltage (always a sine wave).

In the following subsections we are dealing with home-made CTs.

Current Transformers (CTs)

Things to care when dealing with Current Transformers
  • No open-loop use
  • The higher the turns the higher the quality
  • Same goes with the impedance
  • One should care not to saturate the core, keep a 30% current handling margin
Formulaes

Excitation current : delim{|}{dI/dt}{|} = e / L, e is the output voltage (V), L is the inductance (H) and the result is in A/s This current should be at the very most equal to a 10th of the minimum sample current.

Measured voltage : V_eff = R * I_eff / n, R is the burden resistor (Ω), Ieff is the primary current and the result is in V.

Fixed load

In this case we just need a way to know whether the monitored device is powered or not. Simple apparatus like CT + rectifier + smoother + detector may be used.

Resistive load

In this case we are interested in the peak value of the current. CT + rectifier + well designed smoother will do.

Unpredictable load

Most complicate case since we need to get the RMS value of the current. CT + ADE7755 + constant voltage feed seems to be a good solution.

Main supply

The main panel streams data about consumption by itself, only a few components are needed to get the data.

Water

The water meter emits data on a regular basis using an open-source protocol, we just need a compatible receiver and the according spec.

Temperature

Most simple data to gather, the only concern should be the sturdiness of the outdoor sensor.

Rendering

Data exposure is done using the TCP/IP/HTTP stack from tuxgraphics, latest version is available here.

The device can be asked for individual named values or for a pipe separated list of all available named values.

Code should be as reusable as possible.

Example (WIP) :

main.c
#include <avr/io.h>
#include <stdlib.h>
#include <string.h>
#include "ip_arp_udp_tcp.h"
#include "enc28j60.h"
#include "timeout.h"
#include "avr_compat.h"
#include "net.h"
 
 
//static uint8_t mymac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24};
 
// mac[4] = 0x01 : YHome device
// mac[5] = device id
static uint8_t mymac[6] = {0x40, 0x00, 0x00, 0x00, 0x01, 0x01}; // 0x01 : EDF, 0x02 : Box, 0x03 : Tmp
static uint8_t myip[4] = {192, 168, 0, 201}; // 201 : EDF, 202 : Box, 203 : Tmp ...
 
#define MYWWWPORT 80
 
#define BUFFER_SIZE 550
static uint8_t buf[BUFFER_SIZE+1];
 
 
#define N_MES 4
 
typedef struct {
	uint16_t ips; // count per sec
	uint16_t msp; // 100us per imp
	uint16_t cnt; // 100us counter
} Tmeasure;
 
volatile Tmeasure measure[N_MES];
volatile float sensorips[N_MES] = {139.123, 139.123, 139.123, 139.123};
volatile uint16_t tcnt = 0;
volatile uint8_t fetch = 0;
volatile float I[N_MES];
 
SIGNAL(##INT) {
	uint8_t ch = ##get_ch();
	measure[ch].ips++;
	measure[ch].msp = measure[ch].cnt;
	measure[ch].cnt = 0;
}
 
SIGNAL(TIMER0_COMPARE_A) { // Setup with compare
	TCNT0 = 0x00;
	uint8_t i;
	for(i=0; i<N_MES; i++) measure[i].cnt++;
	tcnt++;
	if(tcnt < 10000) return;
	// 1s elapsed
	tcnt = 0;
	fetch = 1;
}
 
void init(void) {
	cli();
 
	TCCR0A = 0x00;
	TCCR0B = 0x02; // P = 8
	OCR0A = 0x64; // 64 @ 8MHz, c8 @ 16MHz
	TIMSK0 = 0x02; // CMPA irq en.
 
	// set the clock speed
	CLKPR = (1<<CLKPCE);
	CLKPR = 0; // 8 MHZ
	_delay_loop_1(0); // 120us
 
	//initialize the hardware driver for the enc28j60
	enc28j60Init(mymac);
	enc28j60clkout(2); // change clkout from 6.25MHz to 12.5MHz
	_delay_loop_1(0); // 60us
	enc28j60PhyWrite(PHLCON, 0x476);
	_delay_loop_1(0); // 60us
 
	//init the ethernet/ip layer:
	init_ip_arp_udp_tcp(mymac, myip, MYWWWPORT);
 
	sei();
}
 
void printInt(uint16_t i, char *se) {
	while(i) {
		*se = 0x30 + (uint8_t)(i % 10);
		i /= 10;
		se--;
	}
}
 
void printI(float i, char *s) {
	s[0] = ' ';
	s[1] = '0';
	s[2] = '.';
	s[3] = '0';
	s[4] = '0';
	s[5] = '0';
	printInt((uint16_t)i, s+1);
	printInt((uint16_t)(i * 1000) % 1000, s+5);
}
 
void main(void) {
	uint16_t plen;
 
	uint8_t i;
	char *s[6];
 
	init();
 
	while(1) {
		if(fetch) {
			for(i=0; i<N_MES; i++) if(measure[i].ips > measure[i].msp) {
				I[i] = measure[i].ips / sensorips[i];
			}else{
				I[i] = 10000 / (sensorips[i] * measure[i].msp);
			}
			fetch = 0;
		}
 
		plen = packetloop_icmp_tcp(buf, enc28j60PacketReceive(BUFFER_SIZE, buf));
		if(plen == 0) continue;
		if(strncmp("GET ", (char *)&(buf[plen]), 4) != 0) { // head, post and other methods
			plen = fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\n<h1>401 Unauthorized</h1>"));
		}else if(strncmp("/ ", (char *)&(buf[plen+4]), 2) == 0) { // catch all
			plen = fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nPragma: no-cache\r\n\r\n"));
			for(i=0; i<N_MES; i++) {
				if(i) plen = fill_tcp_data_p(buf, plen, PSTR(" | "));
				printI(I[i], s);
				plen = fill_tcp_data(buf, plen, s);
			}
		}else if((&(buf[plen+5]) >= 0x30) && (&(buf[plen+5]) <= 0x39)) { // specific sensor
			i = &(buf[dat_p+5]) - 0x30;
			plen = fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\nPragma: no-cache\r\n\r\n"));
			if(i<N_MES) {
				printI(I[i], s);
				plen = fill_tcp_data(buf, plen, s);
			}
		}else{
			plen = fill_tcp_data_p(buf, 0, PSTR("HTTP/1.0 401 Unauthorized\r\nContent-Type: text/html\r\n\r\n<h1>401 Unauthorized</h1>"));
		}
		www_server_reply(buf, plen); // send web page data
	}
}
projects/home_monitor/home.txt · Last modified: 2022/06/30 21:13 by 127.0.0.1