Monitor for central heating system (e.g. 2zones+hw) Supports up to 15 temp probes (DS18B20/DS18S20) 3 valve monitors Gas pulse meter recording Use stand-alone or with nodeEnergyServer See http://robdobson.com/2015/09/central-heating-monitor

Dependencies:   EthernetInterfacePlusHostname NTPClient Onewire RdWebServer SDFileSystem-RTOS mbed-rtos mbed-src

main.cpp

Committer:
Bobty
Date:
2015-02-17
Revision:
5:5bccf48799d4
Parent:
4:0d3a207680b0
Child:
6:b7064d33e402

File content as of revision 5:5bccf48799d4:

#include "mbed.h"
#include "EthernetInterface.h"
#include "NTPClient.h"
#include "RdWebServer.h"
#include "GasUseCounter.h"
#include <stdarg.h>

// Web and UDB ports 
const int WEBPORT = 80; // Port for web server
const int BROADCAST_PORT = 42853; // Arbitrarily chosen port number

// Ticker collects data
Ticker ticker;
const int TICK_MS = 250;

// Debugging and status
RawSerial pc(USBTX, USBRX);
DigitalOut led1(LED1); //ticking (flashes)
DigitalOut led2(LED2); //server listning status (flashes)
DigitalOut led3(LED3); //socket connecting status
DigitalOut led4(LED4); //server status

// Web server
EthernetInterface eth;
NTPClient ntp;
UDPSocket sendUDPSocket;
Endpoint broadcastEndpoint;

// File system for SD card
SDFileSystem sd(p5, p6, p7, p8, "sd");

// Gas use counter
DigitalIn gasPulsePin(p21);
const char* gasPulseFileName = "/sd/curPulse.txt";
const char* logFilename = "/sd/log.txt";
GasUseCounter gasUseCounter(gasPulseFileName, gasPulsePin, pc);

void LogData(const char* format, ...)
{
    FILE* fp = fopen(logFilename, "a");
    if (fp == NULL)
    {
        pc.printf ("Log ... Filename %s not found\r\n", logFilename);
    }
    else
    {
        va_list argptr;
        va_start(argptr, format);
        vfprintf(fp, format, argptr);
        va_end(argptr);
        fclose(fp);
    }
}

void SendInfoBroadcast()
{
    led3 = true;
    // Init the sending socket
    sendUDPSocket.init();
    sendUDPSocket.set_broadcasting();
    broadcastEndpoint.set_address("255.255.255.255", BROADCAST_PORT);
    
    // Format message
    char outBuf[200];
    sprintf(outBuf, "{\"e\":[{\"n\":\"gasCount\",\"v\":%d},{\"n\":\"gasPulseRateMs\",\"v\":%d,\"u\":\"ms\"}]}", 
                        gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
    
    // Send
    int bytesToSend = strlen(outBuf);
    int rslt = sendUDPSocket.sendTo(broadcastEndpoint, outBuf, bytesToSend);
    if (rslt == bytesToSend)
    {
        pc.printf("Broadcast Sent ok %s\n", outBuf);
    }
    else if (rslt == -1)
    {
        pc.printf("Broadcast Failed to send %s\n", outBuf);
    }
    else
    {
        pc.printf("Broadcast Didn't send all of %s\n", outBuf);
    }
    
    // Log
    char timeBuf[32];
    time_t seconds = time(NULL);
    strftime(timeBuf, 32, "%Y-%m-%d %H:%M:%S", localtime(&seconds));
    LogData("%s\t%d\t%d ms\n", timeBuf, gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
    
    led3 = false;
}

// Ticker's tick function
void TickFunction()
{
}

char* getGasUseCallback(int method, char* cmdStr, char* argStr)
{
    char* pResp = gasUseCounter.getGasUseCallback(cmdStr, argStr);
    pc.printf("Returning gas use %s\r\n", pResp);
    return pResp;
}

char* setGasUseCallback(int method, char* cmdStr, char* argStr)
{
    pc.printf("Setting gas use count %s\n\r", argStr);
    int newGasUse = 0;
    char* eqStr = strchr(argStr, '=');
    if (eqStr == NULL)
        return "SetGasValue FAILED";
    sscanf(eqStr+1, "%d", &newGasUse);
    gasUseCounter.SetCount(newGasUse);
    return "SetGasValue OK";
}

void http_thread(void const* arg)
{
    char* baseWebFolder = "/sd/";

    RdWebServer webServer;
    webServer.addCommand("", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, "index.htm", false);
    webServer.addCommand("gear-gr.png", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, NULL, true);
    webServer.addCommand("getgascount", RdWebServerCmdDef::CMD_CALLBACK, &getGasUseCallback);
    webServer.addCommand("setgascount", RdWebServerCmdDef::CMD_CALLBACK, &setGasUseCallback);

    webServer.init(WEBPORT, &led4, baseWebFolder);

    webServer.run();
}

void ntp_thread(void const* arg)
{
    while (1)
    {
        pc.printf("Trying to update time...\r\n");
        if (ntp.setTime("0.pool.ntp.org") == 0)
        {
          printf("Set time successfully\r\n");
          time_t ctTime;
          ctTime = time(NULL);
          printf("Time is set to (UTC): %s\r\n", ctime(&ctTime));
        }
        else
        {
          printf("Cannot set from NTP\r\n");
        } 
        // 1 hour
        for (int i = 0; i < 60; i++)
        {
            for (int j = 0; j < 60; j++)
            {
                osDelay(1000);
            }
            pc.printf("Waited %d mins\r\n", i);
        }
    }
}
    
int main()
{
    pc.baud(115200);
    pc.printf("Gas Monitor V2 - Rob Dobson 2014\r\n");

    ticker.attach(&TickFunction,TICK_MS / 1000.0);

    // Get the current count from the SD Card
    gasUseCounter.Init();
    
    // setup ethernet interface
    eth.init(); //Use DHCP
    eth.connect();
    
    pc.printf("IP Address is %s\n\r", eth.getIPAddress());

    Thread ntpTimeSetter(&ntp_thread);
    
    Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 2.25));
    
    while(true)
    {
        osDelay(250);
        led1 = !led1;

        // Service gas count
        if (gasUseCounter.Service())
            SendInfoBroadcast();
    }
}