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

Thermometers.cpp

Committer:
Bobty
Date:
2015-10-16
Revision:
23:fd5a5a9f30bc
Parent:
21:ccf053bab795

File content as of revision 23:fd5a5a9f30bc:

// Handles temperature collection from a number of DS18B20 devices
// Rob Dobson, 2015

#include "Thermometers.h"

#define SHOW_THERMOMETER_DEBUGGING 1
const int DEBUG_EXPECTED_THERMOMETER_COUNT = 3;

Thermometers::Thermometers(int numTempSensorPins, const PinName tempSensorPins[], int serviceIntervalInMs, Logger &logger) :
    _logger(logger)
{
    _numTempSensorPins = numTempSensorPins;
    _tempSensorPins = tempSensorPins;
    _serviceIntervalInMs = serviceIntervalInMs;
    _numThermometerBuses = 0;
    _failAddrCount = 0;
    _failReadCount = 0;
}

void Thermometers::Init()
{
    // Setup the thermometers
    for (int busIdx = 0; busIdx < _numTempSensorPins; busIdx++)
    {
        if (busIdx >= MAX_ONEWIRE_BUSES)
            break;
        _thermometerBuses[busIdx] = new DS18B20(_tempSensorPins[busIdx], _logger);
        DS18B20* pThermBus = _thermometerBuses[busIdx];
        pThermBus->SearchToGetAddresses();
        pThermBus->ReqConvert();
        _numThermometerBuses++;
    }
}

void Thermometers::Service()
{
    int numLoopsPerThermReading = numSecondsBetweenThermReadings*1000/_serviceIntervalInMs;
    int loopCountForRequestingThermReading = numLoopsPerThermReading - (timeForThermReadingInSecs*1000/_serviceIntervalInMs);

    // Check if thermometer addresses need to be got
    if (_countForThermReadings++ == 0)
    {
        if (_countForGetThermometerAddresses++ == 0)
        {
#ifdef SHOW_THERMOMETER_DEBUGGING
            _logger.LogDebug("ThermReqAddr");
#endif
            for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
            {
                DS18B20* pThermBus = _thermometerBuses[busIdx];
                int numTherms = pThermBus->SearchToGetAddresses();
                if (numTherms != DEBUG_EXPECTED_THERMOMETER_COUNT)
                    _failAddrCount++;
            }
            
#ifdef SHOW_THERMOMETER_DEBUGGING
            for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
            {
                DS18B20* pThermBus = _thermometerBuses[busIdx];
                if(_failAddrCount == 0 && _failReadCount == 0)
                {
                    _logger.LogDebug("Therm B%d N%d OK", busIdx, pThermBus->GetNumAddresses());
                }
                else
                {
                    _logger.LogDebug("Therm B%d N%d FailAddr %d FailRead %d", busIdx, pThermBus->GetNumAddresses(),
                            _failAddrCount, _failReadCount);
                }
                for (int addrIdx = 0; addrIdx < pThermBus->GetNumAddresses(); addrIdx++)
                {
                    char buf [40];
                    pThermBus->DebugGetAddress(addrIdx, buf);
                    _logger.LogDebug("Therm B%d N%d %s", busIdx, addrIdx, buf);
                }
            }
#endif
        }
        else if (_countForGetThermometerAddresses > reGetThermometerAddressesAfterNumReadings)
        {
            _countForGetThermometerAddresses = 0;
        }
    }
    else
    {
        // Check if time to request thermometers to take readings
        if (_countForThermReadings == loopCountForRequestingThermReading)
        {
#ifdef SHOW_THERMOMETER_DEBUGGING
//            _logger.LogDebug("ThermReqConv");
#endif
            for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
            {
                DS18B20* pThermBus = _thermometerBuses[busIdx];
                pThermBus->ReqConvert();
            }                
        }
    
        // Check if it is time to get the values from the thermometers
        if (_countForThermReadings > numLoopsPerThermReading)
        {
            _countForThermReadings = 0;
            for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
            {
                DS18B20* pThermBus = _thermometerBuses[busIdx];
                for (int addrIdx = 0; addrIdx < pThermBus->GetNumAddresses(); addrIdx++)
                {
                    double tempValue = pThermBus->ReadTemperature(addrIdx);
                    if (tempValue == DS18B20::INVALID_TEMPERATURE)
                        _failReadCount++;
                }
            }                

#ifdef SHOW_THERMOMETER_DEBUGGING
            char tempStrBuf[140];
            tempStrBuf[0] = 0;
            for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
            {
                DS18B20* pThermBus = _thermometerBuses[busIdx];
                for (int addrIdx = 0; addrIdx < pThermBus->GetNumAddresses(); addrIdx++)
                {
                    time_t timeOfReading = 0;
                    double tempValue = pThermBus->GetLatestTemperature(addrIdx, timeOfReading);
                    int ageInSecs = time(NULL) - timeOfReading;
                    if (tempValue == DS18B20::INVALID_TEMPERATURE)
                        sprintf(tempStrBuf+strlen(tempStrBuf), "%.1fC (INVALID) ", tempValue);
                    else if (ageInSecs <= 2)
                        sprintf(tempStrBuf+strlen(tempStrBuf), "%.1fC ", tempValue);
                    else
                        sprintf(tempStrBuf+strlen(tempStrBuf), "%.1fC (%dS ago) ", tempValue, ageInSecs);
                }
            }
            _logger.LogDebug("Therm %s", tempStrBuf);
#endif

        }        
    }
}

int Thermometers::GetTemperatureValues(int maxTempValues, TemperatureValue* tempValues, int maxAgeInSecs)
{
    // Go through available values
    int curTempValueIdx = 0;
    for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
    {
        DS18B20* pThermBus = _thermometerBuses[busIdx];
        for (int addrIdx = 0; addrIdx < pThermBus->GetNumAddresses(); addrIdx++)
        {
            time_t timeOfReading = 0;
            double tempValue = pThermBus->GetLatestTemperature(addrIdx, timeOfReading);
            if (tempValue != DS18B20::INVALID_TEMPERATURE)
            {
                if ((time(NULL) - timeOfReading) < maxAgeInSecs)
                {
                    tempValues[curTempValueIdx].timeStamp = timeOfReading;
                    strncpy(tempValues[curTempValueIdx].address, pThermBus->GetAddressStr(addrIdx), DS18B20::ONEWIRE_ADDR_STRLEN-1);
                    tempValues[curTempValueIdx].tempInCentigrade = tempValue;
                    curTempValueIdx++;
                    if (curTempValueIdx >= maxTempValues)
                        break;
                }
            }
        }
        if (curTempValueIdx >= maxTempValues)
            break;
    }
    return curTempValueIdx;
}