DS18B20 Temp sensor playing up!

Hi there,

I’m having an issue with the DS18B20 temp sensor connected to the Photon, I tried 2 different sensors and tried several Libraries and all of them return the same problem, the temperature fluctuates to -0.062 at random times, I’ve included the Crc Check and the “if(abs(oldcelsius-celsius>20)) return;” but the problem still.

DS18B20 supply from TX(HIGH, I’ve tried with 5V) and 10K resistor pull-up. I’ve attached the graph preview from Blynk. The temp fluctuation affects my PID. The whole system is a HomeBrew,

void GetTemp(){
    if(!ds18b20.search()){
      ds18b20.resetsearch();
      celsius = ds18b20.getTemperature();
      Serial.println(celsius);
      while (!ds18b20.crcCheck() && dsAttempts < 4){
        dsAttempts++;
        if (dsAttempts == 3){
          delay(1000);
        }
        ds18b20.resetsearch();
        celsius = ds18b20.getTemperature();
        continue;
      }
      dsAttempts = 0;
      DS18B20nextSampleTime = millis() + DS18B20_SAMPLE_INTERVAL;
    }
    if(abs(oldcelsius-celsius>20)) return;
    oldcelsius=celsius;
}

Hi @lbispo

Are you using parasite power, that is just two wires (power/data and gnd) or are you using normal mode with three wires (power, data and gnd) and just connecting power to TX?

How long are your wires?

Finally, 10K is large for the pull-up; 4.7k is the recommended value.

Hi,

I’m using normal mode, 3 wires. and ds.write(0x44, 0). Wires are about 1.5m it seems to me that the sensor would be faulty the problem is that I’ve tried with 2 different ones.

Do you reckon that reading the raw scratchpad would help?

Hi @lbispo

I recommend you try a few things to find out why the sensors aren’t working. The bad data you are seeing indicates that the return value is all 1’s in binary which is a big clue. It could be hardware or software, but the hardware is easy to test:

  • First I would try shorter wires. 1.5m is medium length but that coupled with your too high pull-up resistor could be a problem.

  • Second I would try changing the 10k ohm pull-up to a 4.7k ohm pull-up resistor

  • I would power the device from 3.3V instead of TX and see if that helps. You should also make sure you power up the sensor for quite some time (several milliseconds at least) before taking a reading

I think these changes will make it work much more reliably.

If that doesn’t work, you could try adding bypass caps (say 10uF and 0.1uF) near the sensors. If you really need 1.5m cables, this is also good advice.

Hi @bko,

Thanks for you advice, I’ve tried powering directly from 3.3V pin and with the 4.7k resistor but it didn’t work.

I can’t shorten the cable as it’s a sealed waterproof sensor. :confused:

I’ll try the capacitors but I’m probably going to change the sensor for an ordinary thermistor.

What library are you using?
Judging by your code snippet, I'd guess it's the DS18B20 library available on Paritlce Build.
If so and you are using the sensor on a single drop bus (only one sensor on the bus) I'd recommend a slightly altered library

1 Like

Hi,

You are right, my latest library is the DS18B20 + Particle-Onewire forked from the Web IDE. But I have tried Dallas and a couple more, all of them had some sort of problem.

Tried to access the link but “Sorry, you don’t have access to that topic!” message show up.

Sorry, that link was in a locked category.
I’ve now quoted the final post from that thread above.

This is my adapted code
DS18B20.h

#pragma once

#include "Particle.h"
#include "OneWire/OneWire.h"

#define MAX_NAME 8
#define MAX_RETRIES 3

// Device resolution
#define TEMP_9_BIT  0x1F //  9 bit
#define TEMP_10_BIT 0x3F // 10 bit
#define TEMP_11_BIT 0x5F // 11 bit
#define TEMP_12_BIT 0x7F // 12 bit
//Parasite Powered or Not
#define READPOWERSUPPLY 0xB4

class DS18B20{
  private:
    OneWire* ds;
    byte data[12];
    byte addr[8];
    byte type_s;
    byte chiptype;
    byte _dataCRC;
    byte _readCRC;
    bool _singleDrop;
    char szName[MAX_NAME];

  public:
    DS18B20(uint16_t pi, bool singleDrop = false);
    boolean search();
    void resetsearch();
    void setResolution(uint8_t newResolution);
    bool readPowerSupply();
    void getROM(char szROM[]);
    byte getChipType();
    char* getChipName();
    float getTemperature(bool forceSelect = false);
    float convertToFahrenheit(float celsius);
    bool crcCheck();
};

DS18B20.cpp

#include "DS18B20.h"


DS18B20::DS18B20(uint16_t pin, bool singleDrop)
: _singleDrop(singleDrop) {
  ds = new OneWire(pin);
}

boolean DS18B20::search() {
  boolean isSuccess =  ds->search(addr);

  if(isSuccess){
    chiptype = addr[0];

    switch (addr[0]) {
      case 0x10:  sprintf(szName, "DS18S20"); type_s = 1; break;
      case 0x28:  sprintf(szName, "DS18B20"); type_s = 0; break;
      case 0x22:  sprintf(szName, "DS1822" ); type_s = 0; break;
      default  :  sprintf(szName, "Unknown"); type_s = 0; break;
    }
  }
  return isSuccess;
}

void DS18B20::resetsearch() {
  ds->reset_search();
}

void DS18B20::setResolution(uint8_t newResolution) {
  ds->reset();
  ds->select(addr);
  switch (newResolution){
  case 12:
    ds->write(TEMP_12_BIT);
    break;
  case 11:
    ds->write(TEMP_11_BIT);
    break;
  case 10:
    ds->write(TEMP_10_BIT);
    break;
  case 9:
  default:
    ds->write(TEMP_9_BIT);
    break;
  }
  HAL_Delay_Milliseconds(20);
  ds->reset();
}

bool DS18B20::readPowerSupply() {
  bool ret = false;
  ds->reset();
  ds->select(addr);
  ds->write(READPOWERSUPPLY);
  if (ds->read_bit() == 0) ret = true;
  ds->reset();
  return ret;
}

void DS18B20::getROM(char szROM[]) {
  sprintf(szROM, "%X %X %X %X %X %X %X %X", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
}

byte DS18B20::getChipType() {
  return chiptype;
}

char* DS18B20::getChipName() {
  return szName;
}

float DS18B20::getTemperature(bool forceSelect) {
  ds->reset();
  if (_singleDrop && !forceSelect)
    ds->skip();
  else
    ds->select(addr);
  ds->write(0x44);        // start conversion, with parasite power on at the end
  delay(750);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
  ds->reset();
  if (_singleDrop && !forceSelect)
    ds->skip();
  else
    ds->select(addr);
  ds->write(0xBE);         // Read Scratchpad

  for (int i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds->read();
    //Serial.println("DS Read Data:");
    //Serial.println(data[i], HEX);
    //Serial.println(" ");
  }
  _dataCRC = (OneWire::crc8(data, 8));
  //Serial.println(_dataCRC, HEX);
  _readCRC = (data[8]);
  //Serial.println(_readCRC, HEX);

  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];

  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  return (float)raw / 16.0;
}

float DS18B20::convertToFahrenheit(float celsius) {
  return celsius * 1.8 + 32.0;
}

bool DS18B20::crcCheck() {
  if (_dataCRC != _readCRC) {
    Serial.println("CRC Failed");
    return false;
  }

  return true;
}

And read like this

  // with single drop OneWire bus and using DS18B20::skip() rather than DS18B20::search()
  int i = 0;
  float _temp;
  do {
    _temp = ds18b20.getTemperature();
  } while (!ds18b20.crcCheck() && DS18B20_MAXRETRY > i++);
  tempHive = (i < DS18B20_MAXRETRY) ? _temp : 99.9;
2 Likes

Hi @ScruffR,

Thanks for the code, my PC is out of service at the moment, I’ll try the new code soon and let you know.

Hi @ScruffR,

Just had a chance to test it now, unfortunately didn’t work, stuck on -0.0625 now.

Can you post your full code and a schematic of your setup?
Maybe I can test with one of my devices.
Since the above alterations I had no issue with that sensor.

Have you instantiated your DS18B20 object with the new singleDrop parameter as true?

DS18B20 sensor(sensPin, true);
1 Like

The code is very messy. The only difference between the code that you’ve provided is DS18B20_MAXRETRY = 4 and I used "Particle-OneWire.h" insted of "OneWire/OneWire.h". I feel that the Photon is running very slow after the new programming, even to flash the new code it’s timing out, i reckon it’s stuck in the while loop.

Schematics from the DS18B20 is basically connected to A0 with 10k//10k pull-up resistor to 3.3V.

#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#include "blynk.h"
#include "pid.h"
#include "Particle-OneWire.h"
#include "DS18B20.h"

double Setpoint, Input, Output;
double aggKp=4, aggKi=0.2, aggKd=1;
double consKp=1, consKi=0.05, consKd=0.25;
//PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, PID::DIRECT);
//PID myPID(&Input, &Output, &Setpoint,2,5,1, PID::DIRECT);
PID myPID(&Input, &Output, &Setpoint,1,4,0.15, PID::DIRECT);

#define OLED_RESET D4
Adafruit_SSD1306 display(OLED_RESET);

DS18B20 ds18b20 = DS18B20(A0, true);     // 1-wire signal on pin A0

int DS18B20nextSampleTime;
int DS18B20_SAMPLE_INTERVAL = 2000;
int DS18B20_MAXRETRY =4;
float tempHive; 
int dsAttempts = 0;
int element = D3;       //element PWM
int xaxis = A5;         //X axis buttom
int yaxis = A4;         //Y axis buttom
int swb = A3;           //Press buttom
int pump = D5;          //Pump
float celsius;
float oldcelsius;
float t1;
float t2;
float zeromillis=0;       //zero millis for boil time calculate
int fermentationtime = 0; //fermentation notification;
unsigned long ti=0;       //calculate seconds left
int h = 0;                //calculate minutes left
int t = 0;
int notification = 0; //secure to notify just once
int Tmash = 66;       //Mash cooking Temp
int end=0;            //end of the menu
int X;                //X axis
int Y;                //Y axis
int SW;               //Middle buttom pressed
int tree=0;           //menu tree
int sparge=15;        //sparge time
int timer = 61;            //Mash time in minutes
int tboil = 10;         //Boil timer
int boiltemp=101;     //boil temperature
int hopadd=2;          //Hop addition
int first=60;
int second=15;        //Hop addition timer to the end in minutes
bool conf=false;      //exit menu
int mashtime=1;  //finish of mashtime
int boiltime=0;  //finish of boil time
int aftertemp=0;  //timer after temp reach desired level
int sliderV3=0;

char auth[] = "b4706060e3da4f918ebb75e3277ecb3c";
BLYNK_WRITE(V3)
{
  sliderV3 = param.asInt(); // assigning incoming value from pin V1 to a variable
}

static const unsigned char beer[] = {
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x73, 0xfc, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9c, 0x07, 0xf9, 0xf9, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xf9, 0x00, 0x1e, 0xe7, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0x0c, 0xc7, 0xcf, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xe2, 0x0c, 0xf3, 0xbf, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x5e, 0x3f, 0xbf, 0xcf, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x5f, 0xfb, 0xdc, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xc6, 0x01, 0xf0, 0x51, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x83, 0x00, 0x1e, 0x7f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0x97, 0xf0, 0x3e, 0x6f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xc0, 0xe3, 0xff, 0xff, 0x97, 0xff, 0xff, 0xaf, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0x99, 0xf8, 0x3f, 0xff, 0x83, 0xff, 0xff, 0x28, 0x3f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0x4f, 0xe3, 0x83, 0xff, 0xff, 0x2f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0x83, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xf8, 0xff, 0x87, 0xff, 0xfe, 0x1c, 0x0f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0x7d, 0x97, 0xff, 0xfe, 0x10, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xe3, 0x87, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xe3, 0xbe, 0x44, 0x0f, 0xe3, 0x8f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xc9, 0xbe, 0x47, 0x8f, 0x81, 0xb5, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfb, 0xff, 0xff, 0xfe, 0x11, 0xbe, 0x2f, 0x37, 0xdf, 0x54, 0x1f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfb, 0xff, 0x87, 0xd8, 0xf9, 0xbe, 0x58, 0x7a, 0xc3, 0xef, 0xef, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfb, 0xff, 0x0f, 0x86, 0xe0, 0x3e, 0x5f, 0xf3, 0xfe, 0xaf, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfb, 0xfe, 0x70, 0x26, 0x7b, 0x7e, 0x5f, 0x33, 0xcf, 0xed, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xf9, 0xfc, 0xf1, 0xf7, 0x78, 0x7f, 0x0f, 0xf3, 0xff, 0xae, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfd, 0xfd, 0xf7, 0xff, 0xcc, 0x7f, 0x27, 0xf3, 0xff, 0xaf, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xf8, 0xf0, 0x00, 0x0c, 0x0f, 0x27, 0xc3, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfd, 0xf8, 0xf0, 0x00, 0x0c, 0xf7, 0xaf, 0xa3, 0xdf, 0xd7, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfd, 0xf8, 0xf1, 0x80, 0x0c, 0xf8, 0xf7, 0x63, 0x6f, 0xb9, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfd, 0xf8, 0xf1, 0x80, 0x0c, 0xfd, 0xfb, 0x7f, 0xf7, 0x3c, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0xf2, 0xf1, 0x80, 0x00, 0xf5, 0x7e, 0xff, 0xff, 0x7f, 0x3f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0xf0, 0xe1, 0x80, 0x00, 0x74, 0xf3, 0x8f, 0x9f, 0x7f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0xf0, 0xe1, 0x80, 0x00, 0x7c, 0xf1, 0xc0, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0xe0, 0xe1, 0x80, 0x00, 0x79, 0xf9, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0xe2, 0xe1, 0x80, 0x00, 0x11, 0xfe, 0xf3, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0xe2, 0xe1, 0x80, 0x00, 0x79, 0x9e, 0xf8, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x40, 0xe1, 0x80, 0x00, 0x7d, 0x6e, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x62, 0xe1, 0x80, 0x00, 0x75, 0x67, 0x7f, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x00, 0xe1, 0x80, 0x00, 0x75, 0xb1, 0xbf, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x90, 0xe1, 0x80, 0x00, 0x7d, 0xd8, 0x9f, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x90, 0xe1, 0x80, 0x00, 0x7d, 0xe0, 0x6f, 0x8c, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x70, 0xe1, 0x80, 0x00, 0x72, 0xf0, 0x70, 0xcc, 0x1f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xb0, 0xe1, 0x80, 0x00, 0x04, 0x60, 0x3f, 0xc6, 0x03, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x30, 0xe1, 0x80, 0x00, 0x78, 0x80, 0x1f, 0xc2, 0x00, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x90, 0xe1, 0x80, 0x00, 0x7d, 0xc0, 0x0f, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd1, 0xe1, 0x80, 0x00, 0x7c, 0xc0, 0x07, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd1, 0xe1, 0x80, 0x00, 0x6c, 0x80, 0x03, 0xec, 0x00, 0x1f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd0, 0xe1, 0x80, 0x00, 0x7c, 0x80, 0x01, 0xe3, 0x00, 0x1f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd0, 0xe1, 0x80, 0x00, 0x7b, 0x00, 0x00, 0xe1, 0x00, 0x0f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd0, 0xe1, 0x80, 0x00, 0x70, 0x00, 0x00, 0x6c, 0x00, 0x0f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd1, 0xe1, 0x80, 0x00, 0x50, 0x00, 0x00, 0x23, 0x00, 0x0f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd0, 0x80, 0x00, 0x04, 0x74, 0x00, 0x00, 0x01, 0x80, 0x0f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd0, 0x00, 0x00, 0x0e, 0x74, 0x00, 0x00, 0x0c, 0x00, 0x1f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd1, 0x20, 0x40, 0x60, 0x24, 0x00, 0x00, 0x07, 0x00, 0x3f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd3, 0x04, 0x0c, 0x40, 0x68, 0x00, 0x00, 0x01, 0x80, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd2, 0x0c, 0x18, 0x00, 0x48, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd2, 0x08, 0x10, 0x00, 0x4f, 0xf8, 0x00, 0x03, 0x03, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd2, 0x08, 0x10, 0x00, 0x7f, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd2, 0x08, 0x10, 0x40, 0x7f, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd2, 0x08, 0x00, 0x40, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xd2, 0x00, 0x10, 0x41, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xcb, 0x07, 0x00, 0x01, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};

static const unsigned char alarm[] = {
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0x80, 0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0x81, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xfe, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xfe, 0x07, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xfc, 0x0e, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xfc, 0x1e, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xf8, 0x38, 0x0f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xf8, 0x38, 0x1e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xf0, 0x70, 0x38, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xe0, 0xe0, 0x78, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xe0, 0xe0, 0xe0, 0x3f, 0x80, 0x3f, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xe0, 0xe1, 0xe0, 0x7f, 0x80, 0x1f, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xc1, 0x81, 0xc0, 0xfe, 0x00, 0x07, 0xff, 0xf9, 0x81, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xc3, 0x83, 0x83, 0xfe, 0x00, 0x07, 0xff, 0xf1, 0xc1, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x83, 0x83, 0x83, 0xfc, 0x0f, 0x03, 0xff, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x83, 0x87, 0x07, 0xfc, 0x1f, 0x83, 0xfc, 0x70, 0xe1, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x83, 0x07, 0x07, 0xf8, 0x3f, 0xc1, 0xf0, 0x70, 0x60, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x87, 0x0e, 0x0f, 0xf8, 0x3f, 0xc1, 0xf0, 0x70, 0x70, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x87, 0x0e, 0x0f, 0xf0, 0x7f, 0xc1, 0xf8, 0x30, 0x70, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x87, 0x0e, 0x1f, 0xf0, 0xff, 0xc1, 0xfc, 0x38, 0x70, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x0e, 0x1f, 0xe0, 0xff, 0xc1, 0xfc, 0x18, 0x30, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x0e, 0x3f, 0xe0, 0xff, 0xc1, 0xfc, 0x1c, 0x30, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x1c, 0x3f, 0xe0, 0xff, 0xc1, 0xfc, 0x1c, 0x30, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x1c, 0x3f, 0xe1, 0xff, 0xc1, 0xfc, 0x1c, 0x38, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x1c, 0x3f, 0xc1, 0xff, 0xc1, 0xfe, 0x1c, 0x38, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x1c, 0x3f, 0x83, 0xff, 0xc3, 0xfe, 0x1c, 0x38, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x1c, 0x3f, 0x03, 0xff, 0xc3, 0xfe, 0x1c, 0x38, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x0c, 0x3e, 0x03, 0xff, 0x83, 0xfc, 0x1c, 0x38, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x0e, 0x0e, 0x3e, 0x0f, 0xff, 0x87, 0xfc, 0x1c, 0x38, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x8e, 0x0e, 0x1c, 0x1f, 0xff, 0x87, 0xfc, 0x1c, 0x30, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x86, 0x0e, 0x18, 0x03, 0xff, 0x87, 0xfc, 0x1c, 0x30, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x86, 0x0e, 0x08, 0x00, 0xff, 0x87, 0xfc, 0x38, 0x70, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x83, 0x0e, 0x0c, 0x00, 0x07, 0x83, 0xf8, 0x38, 0x70, 0x7f, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x83, 0x07, 0x0f, 0x80, 0x00, 0xc1, 0xf8, 0x70, 0x70, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0x83, 0x83, 0x0f, 0xe0, 0x00, 0x01, 0xf0, 0x70, 0x70, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xc3, 0x83, 0xff, 0xff, 0x00, 0x01, 0xf0, 0x70, 0xe0, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xc1, 0x83, 0xff, 0xf8, 0x00, 0x01, 0xc0, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xe1, 0xcf, 0xff, 0xf8, 0x0c, 0x03, 0xc1, 0xc1, 0xc1, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xf8, 0x0f, 0xc3, 0x01, 0xc1, 0xc1, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0x03, 0xc3, 0xc3, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xfe, 0x1f, 0xfc, 0x07, 0x03, 0x83, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0x07, 0x07, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1c, 0x07, 0x07, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7c, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x70, 0x1c, 0x0f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3c, 0x1f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x70, 0x1f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};

static const unsigned char heart[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x03, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x78, 0x00, 0xf0, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x3c, 0x01, 0xc0, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x0e, 0x07, 0xc0, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x8e, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, 0xdc, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

/*static const unsigned char LOGO16_GLCD_BMP[] =
{ 0B11111111, 1111111111,
  0B11111111, 0B11000000,
  0B11111111, 0B11000000,
  0B00000011, 0B11100000,
  0B11110011, 1111111111111,
  0B11111110, 1111111110,
  0B01111110, 0B11111111,
  0B00110011, 0B10011111,
  0B00011111, 0B11111100,
  0B00001101, 0B01110000,
  0B00011011, 0B10100000,
  0B00111111, 0B11100000,
  0B00111111, 0B11110000,
  0B01111100, 0B11110000,
  0B01110000, 0B01110000,
  0B00000000, 0B00110000 };*/

void setup()   {
  Serial.begin(9600);
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  myPID.SetMode(PID::AUTOMATIC);

  // init done
  Blynk.begin(auth);
  //display.display(); // show splashscreen
  display.clearDisplay();   // clears the screen and buffer
  pinMode(xaxis, INPUT);           //X axis buttom
  pinMode(yaxis, INPUT);           //Y axis buttom
  pinMode(swb, INPUT);           //Press buttom
  pinMode(element, OUTPUT);          //Element PWM
  pinMode(pump, OUTPUT);          //Pump
  digitalWrite(pump, HIGH);
}

void loop() {
  Blynk.run();

    //while (end<1){
    //startmenu(); }

  if (millis() > DS18B20nextSampleTime) {
    GetTemp();
    Blynk.virtualWrite(V1,celsius);
  }

  if (mashtime==1){
    Setpoint=Tmash-3;
    PIDcontrol();

  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print("Mash "); display.print(h); display.print(":"); display.print(ti);
  display.setCursor(0,16);
  display.print("Target "); display.print(Tmash); display.print("C");
  display.setCursor(00,34);
  display.setTextSize(3);
  display.print("T="); display.print(celsius,1); display.print("C");
  display.display();

  if(celsius>=Tmash) {
    aftertemp++;
    if (aftertemp<=1){
    zeromillis = millis();  }  }

  if (aftertemp>=1){
    //ALARM DISPLAY AND NOTIFICATION SETTINGS
    if (celsius < (Tmash-5) || celsius > (Tmash+5)){
      t1 = (millis()-t1)/1000;
      t2 = t2+t1;
      if  (notification<1 && t2>20){                    //NOTIFY ONCE AFTER 20SEC
        Blynk.notify("We have a problem");
        notification++;
        t2=0;
      }
      if (t2>20){                                     //SCREEN ALARM EVERY 20SEC
        display.clearDisplay();
        display.drawBitmap(0, 0, alarm, 128, 64, 1);
        display.display();
        delay (1000);
        t2=0;
      }
    }
    else{
      t1=0;
      t2=0;
      notification = 0;
    }
    // splash screen beer/heart
    if (t==8){
      display.clearDisplay();
      display.drawBitmap(0, 0,  heart, 128, 64, 1);
      display.display();
      delay(1000);
      display.clearDisplay();
      display.drawBitmap(0, 0,  beer, 128, 64, 1);
      display.display();
      delay(1000);
      t=0;
    }
  t++;
  t1 = millis();

  h=(timer*60*1000-(millis()-zeromillis))/60000;   //calculate minutes left
  ti=(timer*60*1000-(millis()-zeromillis)-h*60000)/1000;   //calculate seconds left
  Blynk.virtualWrite(V0,h);
  digitalWrite(pump, LOW);                //turn pump On

  }
  else h=timer;
  if (h==0 && ti==0) {
    boiltime++;
    mashtime--;
    aftertemp=0;
    h=tboil;
    digitalWrite(pump, HIGH);                //turn pump Off
    Blynk.notify("SPARGE TIME");
    tree=0;
  }
}

    if (boiltime==1){

      SW = digitalRead(swb);
      if (SW==LOW) tree++;
      if (tree==0){
      analogWrite(element,0,50);
      display.clearDisplay();
      display.setTextSize(2);
      display.setCursor(0,0);
      display.print("Is sparge over?");
      display.setCursor(36,36);
      display.setTextColor(BLACK, WHITE); display.print("YES");
      display.display();
      }
      if (tree>=1){
      Setpoint=boiltemp;
      PIDcontrol();

    display.clearDisplay();
    display.setCursor(0,0);
    display.setTextColor(WHITE);
    display.setTextSize(2);
    display.print("BOIL "); display.print(h); display.print(":"); display.print(ti);
    display.setCursor(0,16);
    display.print("Target "); display.print(boiltemp); display.print("C");
    display.setCursor(00,34);
    display.setTextSize(3);
    display.print("T="); display.print(celsius,1); display.print("C");
    display.display();

      if(celsius>=boiltemp) {
        aftertemp++;
        if (aftertemp<=1){
        zeromillis = millis();  }
      }
      if (aftertemp>=1){
      //ALARM DISPLAY AND NOTIFICATION SEETINGS
      if (celsius < (boiltemp-5) || celsius > (boiltemp+5)){
        t1 = (millis()-t1)/1000;
        t2 = t2+t1;
        if  (notification<1 && t2>20){                    //NOTIFY ONCE AFTER 20SEC
          Blynk.notify("AZEDOU");
          notification++;
          t2=0;
        }
        if (t2>20){                                     //SCREEN ALARM EVERY 20SEC
          display.clearDisplay();
          display.drawBitmap(0, 0, alarm, 128, 64, 1);
          display.display();
          delay (1000);
          t2=0;
        }
      }
      else{
        t1=0;
        t2=0;
        notification = 0;
      }
      // splash screen beer/heart
      if (t==8){
        display.clearDisplay();
        display.drawBitmap(0, 0,  heart, 128, 64, 1);
        display.display();
        delay(1000);
        display.clearDisplay();
        display.drawBitmap(0, 0,  beer, 128, 64, 1);
        display.display();
        delay(1000);
        t=0;
      }
    t++;
    t1 = millis();

    h=(tboil*60*1000-(millis()-zeromillis))/60000;   //calculate minutes left
    ti=(tboil*60*1000-(millis()-zeromillis)-h*60000)/1000;   //calculate seconds left
    Blynk.virtualWrite(V0,h);
    if (h==second && ti==0) Blynk.notify("ADD HOP");
    }
    if (h==0 && ti==0) {
      boiltime++;
      mashtime--;
    }
    // splash screen beer/heart
    if (t==8){
      display.clearDisplay();
      display.drawBitmap(0, 0,  heart, 128, 64, 1);
      display.display();
      delay(1000);
      display.clearDisplay();
      display.drawBitmap(0, 0,  beer, 128, 64, 1);
      display.display();
      delay(1000);
      t=0;
    }
  }
  }

  if (boiltime==2 && mashtime==-1) {
    analogWrite(element,0,50);
    if (fermentationtime<1){
    Blynk.notify("FERMENTATION TIME");
    fermentationtime++;    }
    display.clearDisplay();
    display.setCursor(00,10);
    display.setTextSize(3);
    display.println("TO THE");display.println("Fermenter");
    display.display();
  }
}

void GetTemp(){
    /*if(!ds18b20.search()){
      ds18b20.resetsearch();
      celsius = ds18b20.getTemperature();
      Serial.println(celsius);
      while (!ds18b20.crcCheck() && dsAttempts < 4){
        dsAttempts++;
        if (dsAttempts == 3){
          delay(1000);
        }
        ds18b20.resetsearch();
        celsius = ds18b20.getTemperature();
        continue;
      }
      dsAttempts = 0;
      DS18B20nextSampleTime = millis() + DS18B20_SAMPLE_INTERVAL;
    }
    if(abs(oldcelsius-celsius>20)) return;
    oldcelsius=celsius;*/
    int i = 0;
    do {
    celsius = ds18b20.getTemperature();
    } while (!ds18b20.crcCheck() && DS18B20_MAXRETRY > i++);
    tempHive = (i < DS18B20_MAXRETRY) ? celsius : 99.9;
}

void PIDcontrol(){
  Input = celsius;
  myPID.Compute();
  if (sliderV3!=0) Output=sliderV3;
  Blynk.virtualWrite(V2, map(Output,0,255,0,100));
  Output=Output*0.53;                 //Limit Element to 10A = 2400Watts
  analogWrite(element,Output,50);     //Output PIN to be set up
}

Hi @ScruffR,

Apparently is working fine now, I forgot to flash after change the Single drop to True. I’ll leave it logging overnight.

Thanks for your support.

2 Likes

Working like a charm now

3 Likes