/**
 * Prints the temperature information for our sensors onto the touchscreen.
 * @returns Time it took to run the function
 */
unsigned long Ohmbrewer::Thermostat::displayThermTemp(Ohmbrewer::Screen *screen) {
    unsigned long start = micros();
    //"Temp °C:  88.0  90.0"
    //         current target
    // If current == target, we'll default to yellow, 'cause we're golden...
    uint16_t color = screen->YELLOW;

    if(getSensor()->getTemp()->c() > getTargetTemp()->c()) {
        // above target temp
        color = screen->RED;
    } else if(getSensor()->getTemp()->c() < getTargetTemp()->c()) {
        // below target temp
        color = screen->CYAN;
    }
    //Label
    screen->setTextColor(screen->WHITE, screen->DEFAULT_BG_COLOR);
    screen->print("Temp ");
    screen->writeDegree();
    screen->print("C:");
    //Temps
    getSensor()->getTemp()->displayTempC(color, screen);
    screen->print(" "); //margin
    getTargetTemp()->displayTempC(screen->YELLOW, screen);

    screen->resetTextColor();

    screen->println("");

    return micros() - start;
}
/**
 * Controls all the inner workings of the PID functionality
 * Should be called by _timer
 *
 * Controls the heating element Relays manually, overriding the standard relay
 * functionality
 *
 * The pid is designed to Output an analog value, but the relay can only be On/Off.
 *
 * "time proportioning control"  it's essentially a really slow version of PWM.
 * first we decide on a window size. Then set the pid to adjust its output between 0 and that window size.
 * lastly, we add some logic that translates the PID output into "Relay On Time" with the remainder of the
 * window being "Relay Off Time"
 *
 * PID Adaptive Tuning
 * You can change the tuning parameters.  this can be
 * helpful if we want the controller to be agressive at some
 * times, and conservative at others.
 *
 */
void Ohmbrewer::Thermostat::doPID(){
    getSensor()->work();

    setPoint = getTargetTemp()->c();        //targetTemp
    input = getSensor()->getTemp()->c();//currentTemp
    double gap = abs(setPoint-input);   //distance away from target temp
    //SET TUNING PARAMETERS
    if (gap<10) {  //we're close to targetTemp, use conservative tuning parameters
        _thermPID->SetTunings(cons.kP(), cons.kI(), cons.kD());
    }else {//we're far from targetTemp, use aggressive tuning parameters
        _thermPID->SetTunings(agg.kP(), agg.kI(), agg.kD());
    }
    //COMPUTATIONS
    _thermPID->Compute();
    if (millis() - windowStartTime>windowSize) { //time to shift the Relay Window
        windowStartTime += windowSize;
    }
    //TURN ON
    if (getState() && gap!=0) {//if we want to turn on the element (thermostat is ON)
        //TURN ON state and powerPin
        if (!(getElement()->getState())) {//if heating element is off
            getElement()->setState(true);//turn it on
            if (getElement()->getPowerPin() != -1) { // if powerPin enabled
                digitalWrite(getElement()->getPowerPin(), HIGH); //turn it on (only once each time you switch state)
            }
        }
        //RELAY MODULATION
        if (output < millis() - windowStartTime) {
            digitalWrite(getElement()->getControlPin(), HIGH);
        } else {
            digitalWrite(getElement()->getControlPin(), LOW);
        }
    }
    //TURN OFF
    if (gap == 0 || getTargetTemp()->c() <= getSensor()->getTemp()->c() ) {//once reached target temp
        getElement()->setState(false); //turn off element
        getElement()->work();
//        if (getElement()->getPowerPin() != -1) { // if powerPin enabled
//            digitalWrite(getElement()->getPowerPin(), LOW); //turn it off too TODO check this
//        }

        // Notify Ohmbrewer that the target temperature has been reached.
        Publisher pub = Publisher(new String(getStream()),
                                  String("msg"),
                                  String("Target Temperature Reached."));
        pub.add(String("last_read_time"),
                String(getSensor()->getLastReadTime()));
        pub.add(String("temperature"),
                String(getSensor()->getTemp()->c()));
        pub.publish();
    }
}
Example #3
0
/** Heater control routine.
 *	controlTemp - current control temperature (room or composite of rooms)
 *	heaterTemp - current electric heater temperature to control (ref: O1)
 *	outgoingFluidTemp - current outgoing temperature of the fluid 
 *			    (oven + electric heater, ref: O2)
 */
int controlHeater(float controlTemp, float heaterTemp, float outgoingFluidTemp)
{
	/* First check heater is OK (wasn't overheated) */
	if (heaterTemp > heaterCutOffTemp)
	{
		// -- Current date and time
		time_t now = time(NULL);

		// -- Persist failure info
		FILE *fp;
		fp = fopen(configuration.heaterFailurePath, "w");
		if (NULL != fp)
		{
			const char* formatStr = "%s: Heater failure detected t=%4.2f.\r\n";
			fprintf(fp, formatStr, ctime(&now), heaterTemp);
			fclose(fp);
			printf(formatStr, ctime(&now), heaterTemp);
		}
		else
			printf("Cannot write heater failure status file.\n\r");

		setHeater(OFF);
		setPump(ON);

		exit(EXIT_FAIL);
	}

	if (outgoingFluidTemp > configuration.fluidElectricHeaterOffTemp &&
	    outgoingFluidTemp - heaterTemp > configuration.ovenExtraElectricHeaterOffTemp)
	{
		// Other heater has created enough temperature, no need to run electricity
		setHeater(OFF);
		return OFF;
	}
	else if (controlTemp < getTargetTemp())
	{
		setHeater(ON);
//		setPump(ON);
		return ON;
	}
	else if (controlTemp > getTargetTemp() + configuration.tempDelta)
	{
		setHeater(OFF);
		// Dont stop pump until fluid temp will go down
		// Other heat sources may still be on
		return OFF;
	}
	// return current state
	return getHeaterState();
}
Example #4
0
int main(int argc, const char** args)
{
	// -- Set confguration.ini & others directories
	setDirectories();

	// -- Check for previous fatal errors
	if (wasOverheated())
	{
		printf("Previous heater failure detected. Cannot run.\n\r");
		return EXIT_FAIL;
	}

	// -- Load settings from .ini file
	loadSettings();

	initRoomDescriptors();

//	debug stuff
//	printf("%s", asctime(&configuration.arrive));
//	printf("%s", asctime(&configuration.dep));
//	time_t tt = getHeatingStartTime();
//
//	printf("%s", ctime(&tt));
//	printf("%f\n", getTargetTemp());
//
//	printf("%f\n", configuration.tempDelta);
//	printf("%f\n", configuration.fluidPumpOffTemp);
//	return; 
// 	end of debug stuff

	// -- Measure current temperatures and set out the target
	float controlTemp = getControlTemperature();
	float outgoingFluidTemp = getT(outputSensor);
	float ingoingFluidTemp = getT(inputSensor);
	float electricHeaterTemp = getT(heaterSensor);
	float kitchenTemp = getT(kitchenSensor);
	float bathroomTemp = getT(bathRoomSensor);
	float sashaBedroomTemp = getT(childrenSmallSensor); 
	float targetTemp = getTargetTemp();
	

	// -- Control heater and pump
	int heaterState = controlHeater(controlTemp, electricHeaterTemp, outgoingFluidTemp);
	
	// -- Control sauna floor temp
	float saunaFloorTemp = getT(saunaFloorSensor);
	float saunaFloorTargetTemp = configuration.saunaFloorTemp;
	int saunaFloorHeatingState = controlSaunaFloor(saunaFloorTemp, saunaFloorTargetTemp);

	// -- Initizlize temp vector (no paritcular order)
	float tv[10];
	int tvc = 0;
	tv[tvc++] = controlTemp;
	tv[tvc++] = electricHeaterTemp;
	tv[tvc++] = ingoingFluidTemp;
	tv[tvc++] = outgoingFluidTemp;
	tv[tvc++] = bathroomTemp;
	tv[tvc++] = kitchenTemp;
	tv[tvc++] = sashaBedroomTemp;

	int pumpState = controlPump(tv, tvc);

	// -- Individual rooms control
	/* Not tested yet */
	int i;
	for (i=0; i<ROOMS_COUNT; i++)
		controlRoom(&roomControlDescriptors[i], targetTemp);

	// -- Dates: now and when to start heating next time by our arrival
	char nowStr[TBL], onStr[TBL];
	getDateTimeStr(nowStr, TBL, time(NULL));
	getDateTimeStr(onStr, TBL, getHeatingStartTime());

	printf("%s|%4.2f|%4.2f|%4.2f| %4.2f |%4.2f|%4.2f|%4.2f|%4.2f| %4.2f|%4.2f |%4.2f|%d|%d|%4.2f|%d|%c|%c|%4.1f|%4.1f|%s\r\n",
		nowStr,
		electricHeaterTemp,
		ingoingFluidTemp,
		outgoingFluidTemp,
		getT(externalSensor),
		getT(amSensor),
		getT(bedroomSensor),
		getT(cabinetSensor),
		sashaBedroomTemp,
		kitchenTemp,
		bathroomTemp,
		controlTemp,
		heaterState,
		pumpState,
		saunaFloorTemp,
		saunaFloorHeatingState,
		(isPresence() ? 'P' : 'S'),
		(isSaving() ? 'N' : 'D'),
		targetTemp,
		saunaFloorTargetTemp,
		onStr
	);

	return EXIT_OK;
}