Home PageHome weather station

Home weather station

I wanted to make a home weather station by decoding the weather information embedded in the DCF77 time signal. This pages describes how you can do that using a special chip and an arduino.
If you are looking for a ready built weather station you can find an excellent and cheap one here.
Meteotime is transmitted, alongside the time and date information, from the DCF77 transmitter situated at Mainflingen in Germany. In each minute there are 14 bits which are sent and one weather message consists of three consecutive minutes of 14 bits of weather data. So in all 42 bits are used.

 

In Meteotime systems built in to weather stations these 42 bits are all sent to the decoder chip. In addition there are 40 bits needed derived from the time signal itself. This acts as the cypher.
The decoder uses a modified DES algorithm to decode this message and provide the uncoded weather information. Inside the decoder chip the bits 1 and 8 from the first minute are not used. The second part or keytext is derived from the time and all together the data can be constructed according to the  following method. The data needs to be collected from three consecutive minutes so it can be done very slowly. The example uses data with the date & time as follows: 21.07.2014 2:17

meteotimebits

 

meteotimeoverview

 

Below you can see a typical exchange between the decoder chip and the arduino. The 82 bits data is clocked in and the result can be clocked out on the Dataout pin. The transformation to the weather information data in the decoder result is done with a modified version of DES.  This makes decoding difficult but it can be done. On this page you will find the first method to make a home weather station which involves using a special chip which does the decoding for you.

meteotime result
This decoder result is  a message which contains the weather information. So lets see how this decoding is done.

HKW581 Meteotime decoder chip

The first and easiest way to decode meteotime is to use a decoder chip. This has been developed for Meteotime by HKW and is used in many of the commercial weather stations you can find. The chip is called the HKW581 or sometimes DC-IC or Deciphre-IC.
You can find a description here.  Meteotime are providing the weather forecast and their earning model is based on receiving a license fee for every chip that is sold.  As i do not want to undermine their business I have secured a source for the HKW581 chip which includes the royalty for the lifetime of the home weather station you build. You can buy this chip separately or as part of an arduino shield from my webshop.

This chip has pins for: DataIn, DataOut, ClockIn, QOut and BFR (Which stands for Brute Force Reject status. It is a simple handshake with which the arduino talks to the chip. After powerup you must first wait for the warm up period. This can be as long as 40 seconds although i seldomly experienced more than 30.

 

 

 

 

 

 

 

 

 

 

 

 

Then you have to ClockIn the data. You set the first bit on DataIn, and then pulse the ClockIn line.  This you do 82 times for all 82 bits. Once all the data is clocked in the decoding chip calculates the result. If this is done, the QOut pin goes high. From now on the ClockIn is used to clock out the resultant bits (and the data appears on DataOut). If Qout has gone high, the first bit appears on the DataOut pin. Now you give the next ClockIn pulse, then the next bit is on DataOut. This you do 24 times to collect all the bits.

Starting condition all lines low.
Sending data to the chip:                                                 Receiving data from the chip:
–> Set the bit on the DataIn line                                   <– Chip sets QOut to high
–> Set ClockIn to high                                                     –> Read bit from DOut
<– Chip sets QOut to high                                              –> Set ClockIn to high
–> Set ClockIn to low                                                      <– Chip sets QOut put to low
<– Chip sets QOut put to low                                        –> Set ClockIn to low

Below you can find the arduino program that communicates with the HKW581. It is just a demonstration program which sends a 82 bit string to the chip and reads back the result. It then compares the result to the desired result to check if it is correct. It is claimed that the HKW581 has the ability to correct the telegram even if one bit is incorrect. Experiments show that this is not the case. In this demo program the technique for correcting one bit errors is demonstrated. One bit in the 82 bit string is changed and the HKW581 chip calculates the output.  The output telegram should end in ’10’ if it is correct. So by flipping one bit bat a time and looking for this signature in the last two bits in the output telegram one can discover if one bit was wrong.

Show »

//
// HKW581.ino
// 
// Demo of HKW581 decoder chip showing a successfull decode and a failed decode
// Algorithm to correct a 1 bit corrupted signal by repeatedly changing one
// bit in the telegram and looking for the correct result
// It is claimed that this happens in de decoder chip but experiments show that this is not the case.
// The parity bits and comparing the time to previous minute can correct the time key part of the DES.
// Practically this will be used to correct errors in the weather data. This takes 12 seconds to complete.
// This is easily in the three minute window before the next decode is required so that this is a practical proposition.
// Bas Kasteel, 2014
// This example code is in the public domain.
// You may use this software as you see fit as long as this header portion is included.
// Since this program may involve some hardware please note I'm not responsible if you destroy anything while tinkering with this software.
// The program uses a modified version of the library from Thijs Elenbaas, 2012
// You can contact me via www.arduino-projects4u.com
// Date 25:7:2014
// Chanelog:
// 0.1 innitial release

const int ledPin =  3;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated
long interval = 1000;           // interval at which to blink (milliseconds) 
int DataIn = 4;
int DataOut = 6;
int ClockIn = 7;
int QOut = 3;
int BFR = 5;
bool flag = false;
bool debug = true;
String meteodata;
int meteobit;
int h;
unsigned long bitpattern;
unsigned long meteopattern;
//             1234567890123456789012345678901234567890123456789012345678901234567890123456789012
String test =("0100001010001101101010100111100110000110001010000001001000110010000010000101100000");
String test2=("0100001010001101101010100111100110000110011010000001001000110010000010000101100000");
//                                                      * This bit is changed
byte meteoweather[] = {0x00, 0x00, 0x00 };
int invertbit=0;
void setup() {                
  // initialize the digital pin as an output.
  pinMode(ledPin, OUTPUT);      
  pinMode(DataIn, OUTPUT);
  pinMode(DataOut, INPUT);
  pinMode(ClockIn, OUTPUT);
  pinMode(QOut, INPUT);
  pinMode(BFR,INPUT);
  Serial.begin(115200);  
  digitalWrite(DataIn,LOW);
  digitalWrite(ClockIn,LOW);
Serial.println("Decoder powered on and port set up");
delay(5000);
Serial.println("Waiting for decoder warm up max 40sec");
h=0;
do {
delay(1000);Serial.print(h);Serial.print(".");Serial.print("BFR=");Serial.print(digitalRead(BFR));Serial.print("  ");h++;
if (digitalRead(BFR)==0) { flag=true;}
delay(10);
if ((digitalRead(BFR)==0) && (flag==true)) { break;}else{flag=false;}
}
while (1);


Serial.println();
Serial.println("Warm up complete");
//              12345678901234 12345678901234 12345678901234 12345678 12345678 12345678 12345 678 12345678
Serial.println("Datapackage 1  Datapackage 2  Datapackage 3  Time     Hour     Date     month dow year");
invertbit=83;
decode ();
if(meteodata.substring(22,24) == "10") {Serial.println ("Decoder Result OK");} else {Serial.println ("Decoder Result NOT OK");}
Serial.println("Change one bit (bit 42) in telegram ");
test=test2;
Serial.println("Datapackage 1  Datapackage 2  Datapackage 3  Time     Hour     Date     month dow year");
invertbit=83;
decode ();
if(meteodata.substring(22,24) == "10") {Serial.println ("Decoder Result OK");} else {Serial.println ("Decoder Result NOT OK");}
Serial.println("Gives NOT OK so now change 1 bit at a time until found");
debug = false;
// Here routine for single bit correction. Look for correct output inverting each bit.
// If correct then break
unsigned long previousMillis = millis();
for (invertbit=0;invertbit<82;invertbit++) {
decode();
if(meteodata.substring(22,24) == "10") {Serial.print (invertbit);Serial.println (" OK");} else {Serial.print (invertbit);Serial.print(" ");}
if(meteodata.substring(22,24) == "10") {break;} 
}
unsigned long currentMillis = millis();
Serial.print("Time taken to find correct telegram = ");
Serial.print((currentMillis-previousMillis)/1000);
Serial.println(" Seconds");
Serial.print("Corrupted telegram = ");
for (int k=0;k<82;k++) {
if (test.substring(k,k+1)=="1") {meteobit=1;} else {meteobit=0;};
if (k==invertbit) {Serial.print("|");}
Serial.print(meteobit);
if (k==invertbit) {Serial.print("|");}
if (k==13 | k==27 | k==41 | k==49 | k==57 | k==65 | k==70 | k==73){Serial.print(" ");}
}
Serial.println();
Serial.print("Corrected telegram = ");
for (int k=0;k<82;k++) {
if (test.substring(k,k+1)=="1") {meteobit=1;} else {meteobit=0;};
if (k==invertbit) {if (meteobit==1) {meteobit=0;}else{meteobit=1;};}
if (k==invertbit) {Serial.print("|");}
Serial.print(meteobit);
if (k==invertbit) {Serial.print("|");}
if (k==13 | k==27 | k==41 | k==49 | k==57 | k==65 | k==70 | k==73){Serial.print(" ");}
}
}


void loop() {
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;   
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    digitalWrite(ledPin, ledState);
  }
}

void decode() {
  
for (int k=0;k<82;k++) {
if (test.substring(k,k+1)=="1") {meteobit=1;} else {meteobit=0;};
if (k==invertbit) {if (meteobit==1) {meteobit=0;}else{meteobit=1;};}
if (invertbit==83) {Serial.print(meteobit);}
digitalWrite (DataIn,meteobit);
digitalWrite (ClockIn, HIGH);
do {}
while (digitalRead (QOut)==LOW);
digitalWrite (ClockIn, LOW);
do {}
while (digitalRead (QOut)==HIGH);
if (invertbit==83) {if (k==13 | k==27 | k==41 | k==49 | k==57 | k==65 | k==70 | k==73){Serial.print(" ");};}
}
if (debug==true){
Serial.println();
Serial.println("All bits clocked in to decoder");
//do {}
//while (digitalRead (QOut)==LOW);
Serial.println("Decoding now complete");
}
// Collect output data from decoder
bitpattern=0;meteopattern=0;
for (int k=0;k<24;k++){
do {}
while (digitalRead (QOut)==LOW);
meteobit=digitalRead(DataOut);
bitpattern+=meteobit;
bitpattern<<=1;
digitalWrite(ClockIn, HIGH);
do {}
while (digitalRead (QOut)==HIGH);
digitalWrite(ClockIn, LOW);
}
for (int k=1;k<25;k++){
meteobit=(bitpattern>>k)&0x01;
meteopattern+=meteobit;
meteopattern<<=1;
}
if (debug==true) {Serial.print("Decoder result inv = ");}
meteopattern>>=1;
meteodata="";
for (int j=0;j<24;j++){
	bool p = (meteopattern >> j) & 1;
	if (debug==true) {Serial.print(p,DEC);}
        meteodata +=p;
        if (debug==true) {if ((j+1)%8 == 0) {Serial.print(" ");};}
}
if (debug==true) {
Serial.println();
Serial.println("Now must reverse bit string");
Serial.print("Decoder result     = ");
for (int j=23;j>-1;j--){
	bool p = (meteopattern >> j) & 1;
	Serial.print(p,DEC);
        meteodata +=p;
        if ((j)%8 == 0) {Serial.print(" ");}
}

Serial.println();
Serial.print  ("Actual result   = 0x");
meteoweather[0]=meteopattern>>16;meteoweather[1]=meteopattern>>8;meteoweather[2]=meteopattern&0xFF;
if (meteoweather[0]<0x10){Serial.print("0");};Serial.print(meteoweather[0],HEX);Serial.print(" 0x");
if (meteoweather[1]<0x10){Serial.print("0");};Serial.print(meteoweather[1],HEX);Serial.print(" 0x");
if (meteoweather[2]<0x10){Serial.print("0");};Serial.println(meteoweather[2],HEX);
Serial.println("Expected result = 0x7F 0xA9 0x3A");
}
}

Below you can see an example of the output from this program. You can see how the HKW581 finds the error bit in the input string.

HKW581 test

 

If you send an incorrect telegram you allways get the same answer.
00100000  00000000 00000001
Meteotime uses 22 bits of data with 2 bits additionally indicating the status of the decoder.
These status bits are ’10’ if all is OK and ’01’ in case of a failure.

Here is an example input to the DECHIFFRIER-IC 82 bits in total
  1234567890123456789012345678901234567890123456789012345678901234567890123456789012

“0101111000101011010110100111101001100100110100000000000000000011000010010001001000”

And here is the corresponding output.
……………………………..123456789012345678901234 = 24 bits
This gives an output of “011001000000011011000110” including the last two status bits.

So this is all there is to it. Now all you have to do is connect up the HKW581 and program the arduino and away you go.
The connection pins are given in the picture above. (so DataIn is connected to arduino PIN 4 and so on.)
I used a prototyping board and simply wired all connections using small pieces of wire. The audio connector is actually the antenna connector from HKW Electronik. This is quite convenient as you no longer have to worry about loose connections as the EM2S DCFn module and ferrite antenna are mounted inside a plastic box. Perfect solution and very stable. I chose the version in the link above which was 39.50€ and worked perfectly and more stable than the conrad module.

The final step is to translate this decoded weather data into a human understandable form. What the different bits mean is according to a table  http://www.arduino-projects4u.com/pdf/DB%20W-Protokoll-V%201.pdf. This also explains the meaning of the decoded Meteo data. Unfortunately there are some errors in the document. Thomas berends has found solutions to this which he uses on his website. I have made an effort to incorporate these improvements into the software. The following program does the job of translating the raw HKW581 output data into a human readible format. I have by no means done exhaustive testing so it may still contain some errors. (If anyone finds any mistakes please let me know). It uses the flash library from arduiniana which you need to install from here.
If you’re using a version of Arduino IDE newer than 1.5, you need to modify the Flash.h file to include the following lines just after the #include <avr/pgmspace.h> line:
#if ARDUINO >= 150
typedef char prog_char __attribute__((__progmem__));
#endif
Below you can find a screendump from this program. You can see the time the data was collected from was 2hrs 20mins. This means  it is from Region 0-59 and contains night data. The city number can be calculated by looking at the lookup chart. In this case number 26. This makes the city Muenchen in Germany. Then follows the decoding of the weather information.

 

 

Show »

//  bin2weather.ino
//
//  This converts the 24 bit meteotime telegram into a human readable forecast
//  In this example three meteotime weather forecasts are used to demonstrate the principles
//  You can play around with them to get different effects.
//  Bas Kasteel, 2014
//  The program uses a modified version of the library from Thijs Elenbaas, 2012
//  library expanded for weather information
//  You can contact me via www.arduino-projects4u.com
//  Date 25:7:2014
//  Chanelog:
//  0.1 innitial release

//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.

//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.

//  If you want a copy of the GNU Lesser General Public
//  License you can write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#include <avr/pgmspace.h>
#include <Flash.h>    // http://arduiniana.org/libraries/flash/
#include <DCF77.h>    // https://github.com/thijse/Arduino-Libraries/downloads
#include <Time.h>     // http://www.arduino.cc/playground/Code/Time
#define DCF_PIN 2	                      // Connection pin to DCF77 device
#define DCF_INTERRUPT 0		              // Interrupt number associated with pin
time_t time;
DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT);
String meteodata;
String timedata;
int val;
char buffer[32];
int fourdayforecast=0;
int twodayforecast=0;
int temp=0;
int y = 0;
#define SerialPrint(x) SerialPrint_P(PSTR(x))
#define SerialPrintLn(x) SerialPrint_Q(PSTR(x))
int significantweather[60]={0};
String weathermemory[60];
void setup(){
Serial.begin(115200); 
//                   0110  Day critical weather
//                       0001  Night critical weather
//                           0001 Extremeweather
//                               011 Rainprobability
//                                  0  Anomaly
//                                   101101 Temperature
meteodata = String ("111001101100011010110110");//Snow, Heavy rain with thunderstorms, 90%, Heavy weather night, No, 23⁰c
DCF.DCFminute=8;DCF.DCFhour=2;// amsterdam day 
show();digitalClockDisplay();Serial.println();
meteodata = String ("111001100000011011000110");
DCF.DCFminute=8;DCF.DCFhour=5;// amsterdam night
show();digitalClockDisplay();Serial.println();
meteodata = String ("011000010000011011000110");
DCF.DCFminute=8;DCF.DCFhour=23;// amsterdam day 4 wind + 2 day forecast Lissabon
show();digitalClockDisplay();
delay(5000);
}

void loop(){
}

void unbinary(int a, int b){
        val=0;
        for (int i = 0; i < 16; i++) {
        if (! meteodata.substring(a,b) [i]) {
        break;
        }
        val <<= 1;
        val |= (meteodata.substring(a,b) [i] == '1') ? 1 : 0;
        }  
}
void weatherunbinary(int a, int b){
        val=0;
        for (int i = 0; i < 16; i++) {
        if (! weathermemory[fourdayforecast].substring(a,b) [i]) {
        break;
        }
        val <<= 1;
        val |= (weathermemory[fourdayforecast].substring(a,b) [i] == '1') ? 1 : 0;
        }  
}
static int Reverse(int x,int z)
{
y=0;
for (int i = 0; i < z; ++i)
{
y <<= 1;
y |= (x & 1);
x >>= 1;
}
return y;
}

void SerialPrint_P(PGM_P str) {
  for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
}
void SerialPrint_Q(PGM_P str) {
  for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
  Serial.println();
}
void digitalClockDisplay(){
  setTime(0,0,0,25,7,2014);
  SerialPrint("Time: ");
  Serial.print(DCF.DCFhour);
//  SerialPrint(":");
  printDigits(DCF.DCFminute);
  SerialPrint(":00");
  SerialPrint(" Date: ");
  Serial.print(day());
  SerialPrint(".");
  Serial.print(month());
  SerialPrint(".");
  Serial.println(year());
}
void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  SerialPrint(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void show(){

FLASH_STRING_ARRAY (town,
PSTR("F Bordeaux"), PSTR("F la Rochelle"),PSTR("F Paris"),PSTR("F Brest"),PSTR("F Clermont-Ferrand"),PSTR("F Beziers"),PSTR("B Bruxelles"),PSTR("F Dijon"),PSTR("F Marseille"),PSTR("F Lyon"),PSTR("F Grenoble"),PSTR("CH La Chaux de Fonds"),
PSTR("D Frankfurt am Main"),PSTR("D Trier"),PSTR("D Duisburg"),PSTR("GB Swansea"),PSTR("GB Manchester"),PSTR("F le Havre"),PSTR("GB London"),PSTR("D Bremerhaven"),PSTR("DK Herning"),PSTR("DK Arhus"),PSTR("D Hannover"),PSTR("DK Copenhagen"),PSTR("D Rostock"),
PSTR("D Ingolstadt"),PSTR("D Muenchen"),PSTR("I Bolzano"),PSTR("D Nuernberg"),PSTR("D Leipzig"),PSTR("D Erfurt"),PSTR("CH Lausanne"),PSTR("CH Zuerich"),PSTR("CH Adelboden"),PSTR("CH Sion"),PSTR("CH Glarus"),PSTR("CH Davos"),PSTR("D Kassel"),PSTR("CH Locarno"),PSTR("I Sestriere"),
PSTR("I Milano"),PSTR("I Roma"),PSTR("NL Amsterdam"),PSTR("I Genova"),PSTR("I Venezia"),PSTR("D Strasbourg"),PSTR("A Klagenfurt"),PSTR("A Innsbruck"),PSTR("A Salzburg"),PSTR("A/SK Wien/Bratislava"),PSTR("CZ Praha"),PSTR("CZ Decin"),PSTR("D Berlin"),PSTR("S Gothenburg"),
PSTR("S Stockholm"),PSTR("S Kalmar"),PSTR("S Joenkoeping"),PSTR("D Donaueschingen"),PSTR("N Oslo"),PSTR("D Stuttgart"),
PSTR("I Napoli"),PSTR("I Ancona"),PSTR("I Bari"),PSTR("H Budapest"),PSTR("E Madrid"),PSTR("E Bilbao"),PSTR("I Palermo"),PSTR("E Palma de Mallorca"),
PSTR("E Valencia"),PSTR("E Barcelona"),PSTR("AND Andorra"),PSTR("E Sevilla"),PSTR("P Lissabon"),PSTR("I Sassari"),PSTR("E Gijon"),PSTR("IRL Galway"),PSTR("IRL Dublin"),PSTR("GB Glasgow"),PSTR("N Stavanger"),PSTR("N Trondheim"),PSTR("S Sundsvall"),PSTR("PL Gdansk"),
PSTR("PL Warszawa"),PSTR("PL Krakow"),PSTR("S Umea"),PSTR("S Oestersund"),PSTR("CH Samedan"),PSTR("HR Zagreb"),PSTR("CH Zermatt"), PSTR("HR Split"));  


FLASH_STRING_ARRAY (weather,
PSTR("Reserved"),PSTR("Sunny"),PSTR("Partly clouded"),PSTR("Mostly clouded"),PSTR("Overcast"),PSTR("Heat storms"),PSTR("Heavy rain"),PSTR("Snow"),PSTR("Fog"),PSTR("Sleet"),PSTR("Rain showers"),PSTR("light rain"),
PSTR("Snow showers"),PSTR("Frontal storms"),PSTR("Stratus cloud"),PSTR("Sleet storms")); 

FLASH_STRING_ARRAY (heavyweather,
PSTR("None"),PSTR("Heavy Weather 24 hrs."),PSTR("Heavy weather Day"),PSTR("Heavy weather Night"),PSTR("Storm 24hrs."),PSTR("Storm Day"),PSTR("Storm Night"),
PSTR("Wind gusts Day"),PSTR("Wind gusts Night"),PSTR("Icy rain morning"),PSTR("Icy rain evening"),PSTR("Icy rain night"),PSTR("Fine dust"),PSTR("Ozon"),PSTR("Radiation"),PSTR("High water"));     

FLASH_STRING_ARRAY (probprecip,
PSTR("0 %"),PSTR("15 %"),PSTR("30 %"),PSTR("45 %"),PSTR("60 %"),PSTR("75 %"),PSTR("90 %"),PSTR("100 %"));

FLASH_STRING_ARRAY (winddirection,
PSTR("N"),PSTR("NO"),PSTR("O"),PSTR("SO"),PSTR("S"),PSTR("SW"),PSTR("W"),PSTR("NW"),
PSTR("Changeable"),PSTR("Foen"),PSTR("Biese N/O"),PSTR("Mistral N"),PSTR("Scirocco S"),PSTR("Tramont W"),PSTR("reserved"),PSTR("reserved"));

FLASH_STRING_ARRAY (windstrength,
PSTR("0"),PSTR("0-2"),PSTR("3-4"),PSTR("5-6"),PSTR("7"),PSTR("8"),PSTR("9"),PSTR(">=10"));

FLASH_STRING_ARRAY (anomaly1,
PSTR("Same Weather "),PSTR("Jump 1 "),PSTR("Jump 2 "),PSTR("Jump 3 "));

FLASH_STRING_ARRAY (anomaly2,
PSTR("0-2 hrs"),PSTR("2-4 hrs"),PSTR("5-6 hrs"),PSTR("7-8 hrs"));


        fourdayforecast = ((DCF.DCFhour)%3)*20; if (DCF.DCFminute>0) {fourdayforecast+=(DCF.DCFminute-1)/3;}
        if (DCF.DCFminute>0) {twodayforecast=((((DCF.DCFhour)*60)+(DCF.DCFminute-1))%90)/3;}else{twodayforecast=((DCF.DCFhour)*60);}
        twodayforecast+=60;     
        if (DCF.DCFhour<21) //Between 21:00-23:59 significant weather & temperature is for cities 60-89 wind and wind direction for cities 0-59.
        {
        if ((DCF.DCFhour)%6<3){weathermemory[fourdayforecast]=meteodata;weatherunbinary(8,12);Reverse(val,4);significantweather[fourdayforecast]=y;}// Extreme weather is valid from this hour but also +3 hour  
        Serial.print(fourdayforecast);SerialPrint(" ");town[fourdayforecast].print(Serial);Serial.println(); 
        if (((DCF.DCFhour)%6)>2) {SerialPrint("fourday f/c Night =      ");} else {SerialPrint("fourday f/c Day   =      ");}
        Serial.println((DCF.DCFhour/6)+1);//today is 1 tomorrow 2 etc       
        SerialPrint("Day               =   ");Serial.print(meteodata.substring(0,4));SerialPrint(" "); unbinary(0,4);Reverse (val,4); val=y;Serial.print(val,HEX);SerialPrint(" ");temp=val;
        if (temp==5 || temp==6 || temp==13 || temp==7) {
        if (significantweather[fourdayforecast]==1 || significantweather[fourdayforecast]==2) {if (temp !=6) {Serial.print ("Heavy ");};weather[temp].print(Serial);SerialPrintLn(" with thunderstorms");}
        else {weather[temp].print(Serial);Serial.println();}
        }else{weather[temp].print(Serial);Serial.println();}
        SerialPrint("Night             =   ");Serial.print(meteodata.substring(4,8));SerialPrint(" "); unbinary(4,8); Reverse (val,4);val=y;Serial.print(val,HEX);SerialPrint(" ");temp=val;
        if (temp==5 || temp==6 || temp==13 || temp==7) {
        if (significantweather[fourdayforecast]==1 || significantweather[fourdayforecast]==3) {if (temp !=6) {Serial.print ("Heavy ");};weather[temp].print(Serial);SerialPrintLn(" with thunderstorms");}
        else {weather[temp].print(Serial);Serial.println();}
        }else {if (temp==1) {SerialPrint("Clear");;Serial.println();} else {weather[temp].print(Serial);Serial.println();}
        }
        if ((DCF.DCFhour)%6<3){
        SerialPrint("Rainprobability   =    ");Serial.print(meteodata.substring(12,15));SerialPrint(" "); unbinary(12,15);Reverse (val,3);val=y;
        Serial.print(val,HEX);SerialPrint(" ");probprecip[val].print(Serial); Serial.println();
        SerialPrint("Extremeweather    =   "); unbinary(15,16);
        if (val==0) {// DI=0 and WA =0
        Serial.print(weathermemory[fourdayforecast].substring(8,12));SerialPrint(" ");
        Serial.print(significantweather[fourdayforecast],HEX);SerialPrint(" ");heavyweather[significantweather[fourdayforecast]].print(Serial); Serial.println();
        } else {
        Serial.print(meteodata.substring(8,10));SerialPrint(" ");  
        unbinary(8,10);Serial.print(val,HEX);SerialPrint(" ");anomaly1[val].print(Serial); Serial.println();
        SerialPrint("                  =     ");
        Serial.print(meteodata.substring(10,12));SerialPrint(" ");
        unbinary(10,12);Serial.print(val,HEX);SerialPrint(" ");anomaly2[val].print(Serial); Serial.println(); 
        }          
        }
        if ((DCF.DCFhour)%6>2){        
        SerialPrint("Winddirection     =   ");Serial.print(meteodata.substring(8,12));SerialPrint(" ");unbinary(8,12);Reverse (val,4);val=y;
        Serial.print(val,HEX);SerialPrint(" ");winddirection[val].print(Serial); Serial.println();
        SerialPrint("Windstrength      =    ");Serial.print(meteodata.substring(12,15));SerialPrint(" ");unbinary(12,15);Reverse (val,3);val=y;
        Serial.print(val,HEX);SerialPrint(" ");windstrength[val].print(Serial); SerialPrintLn(" Bft");
        SerialPrint("Extremeweather    =   ");
        Serial.print(weathermemory[fourdayforecast].substring(8,12));SerialPrint(" ");
        Serial.print(significantweather[fourdayforecast],HEX);SerialPrint(" ");heavyweather[significantweather[fourdayforecast]].print(Serial); Serial.println();       
        } 
        SerialPrint("Weather Anomality =      ");Serial.print(meteodata.substring(15,16));SerialPrint(" "); unbinary(15,16);Serial.print(val,HEX);
        if (val==1) {SerialPrintLn(" Yes");} else {SerialPrintLn(" No");}
        }
        else
        //*********************************************************************************************************************************
        {
        Serial.print(fourdayforecast);SerialPrint(" ");town[fourdayforecast].print(Serial);Serial.println(); 
        if (((DCF.DCFhour)%6)>2) {SerialPrint("fourday f/c Night =      ");} else {SerialPrint("fourday f/c Day   =      ");}
        Serial.println((DCF.DCFhour/6)+1);//today is 1 tomorrow 2 etc        
        SerialPrint("Winddirection     =   ");Serial.print(meteodata.substring(8,12));SerialPrint(" ");unbinary(8,12);Reverse (val,4);val=y;
        Serial.print(val,HEX);SerialPrint(" ");winddirection[val].print(Serial); Serial.println();
        SerialPrint("Windstrength      =    ");Serial.print(meteodata.substring(12,15));SerialPrint(" ");unbinary(12,15);Reverse (val,3);val=y;
        Serial.print(val,HEX);SerialPrint(" ");windstrength[val].print(Serial); SerialPrintLn(" Bft");
        Serial.print(twodayforecast);SerialPrint(" ");town[twodayforecast].print(Serial);Serial.println();  
        SerialPrint("twoday f/c day    =      ");
        if (((DCF.DCFhour-21)*60+DCF.DCFminute)>90) {SerialPrintLn("2");}else{SerialPrintLn("1");}//today is 1 tomorrow 2 etc                
        SerialPrint("Day               =   ");Serial.print(meteodata.substring(0,4));SerialPrint(" "); unbinary(0,4);Reverse (val,4); val=y;Serial.print(val,HEX);SerialPrint(" ");
        temp=val; unbinary(8,12); Reverse (val,4);val=y;
        weather[temp].print(Serial);Serial.println();
        SerialPrint("Night             =   ");Serial.print(meteodata.substring(4,8));SerialPrint(" "); unbinary(4,8); Reverse (val,4);val=y;Serial.print(val,HEX);SerialPrint(" ");
        if (val==1) {SerialPrint("Clear");;Serial.println();} else {weather[temp].print(Serial);Serial.println();}
        SerialPrint("Weather Anomality =      ");Serial.print(meteodata.substring(15,16));SerialPrint(" "); unbinary(15,16);Serial.print(val,HEX);
        if (val==1) {SerialPrintLn(" Yes");} else {SerialPrintLn(" No");}      
        }
        SerialPrint("Temperature       = ");Serial.print(meteodata.substring(16,22));SerialPrint(" "); unbinary(16,22);Reverse (val,6);val=y;    
        SerialPrint("0x");Serial.print(val,HEX);SerialPrint(" ");
        if (val==0) {SerialPrint("<-21 ");Serial.print(char(176));SerialPrint("C");}
        if (val==63) { Serial.print (">40 ");Serial.print(char(176));SerialPrint("C");}
        if ((val!=0) & (val!=63)) {Serial.print(val-22,DEC);Serial.print(char(176));SerialPrint("C");} 
        // Night temperature is minimum
        // Daytime temperature is daytime maximum       
        if (((DCF.DCFhour)%6)>2 && (DCF.DCFhour<21)) {SerialPrintLn(" minimum");} else {SerialPrintLn(" maximum");}        
        SerialPrint("Decoder status    =     "); 
        Serial.print(meteodata.substring(22,24));
        if(meteodata.substring(22,24) == "10") {Serial.println (" OK");} else {Serial.println (" NOT OK");} 
}


Meteotime decoding

Here finally is the final program. Decoding the DCF77 data and presenting it to the HKW581 chip, receiving a reply and translating this into human readible code. It uses a lot of RAM which means it does not work on an arduino UNO. However both 1280 and 2560 MEGA processors are OK.

Show »

//  DCF77MeteotimeWeather.ino

//  DCF77 weather & time decoding
//  Weather information from three consecutive minutes bits 1-14 of time signal
//  Using HKW581 decoder chip
//  Bas Kasteel, 2014
//  The program uses a modified version of the library from Thijs Elenbaas, 2012
//  library expanded for weather information 
//  You can contact me via www.arduino-projects4u.com
//  Date 25:7:2014
//  Changelog:
//  0.1 innitial release

//  This program is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.

//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.

//  If you want a copy of the GNU Lesser General Public
//  License you can write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  

#include <DCF77.h>                            // https://github.com/thijse/Arduino-Libraries/downloads
#include <Time.h>                             // http://www.arduino.cc/playground/Code/Time
#include <avr/pgmspace.h>
#include <Flash.h>                            // http://arduiniana.org/libraries/flash/


#define DCF_PIN 2	                      // Connection pin to DCF77 device
#define DCF_INTERRUPT 0		              // Interrupt number associated with pin
#define SerialPrint(x) SerialPrint_P(PSTR(x))
#define SerialPrintLn(x) SerialPrint_Q(PSTR(x))


time_t time;
DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT);
int DataIn = 4;
int DataOut = 6;
int ClockIn = 7;
int QOut = 3;
int BFR = 5;

String meteodata;
int val;
char buffer[32];
int fourdayforecast=0;
int twodayforecast=0;
int temp=0;
int y = 0;
int significantweather[60]={0};
String weathermemory[60];

int meteobit;
unsigned long bitpattern;
unsigned long meteopattern;
unsigned long long weatherBuffer = 0;
byte meteoweather[] = {0x00, 0x00, 0x00 };

void setup() {
 Serial.begin(115200); 
for (int i=0;i<61;i++){
weathermemory[i]="";
for (int j=0;j<24;j++){
	bool p = 0;
  weathermemory[i]+=p;
}   
}  
  pinMode(DataIn, OUTPUT);
  pinMode(DataOut, INPUT);
  pinMode(ClockIn, OUTPUT);
  pinMode(QOut, INPUT);
  pinMode(BFR,INPUT);  
  digitalWrite(DataIn,LOW);
  digitalWrite(ClockIn,LOW); 

SerialPrintLn("Decoder powered on and port set up");
SerialPrintLn("Waiting for decoder warm up max 40sec");

do {
delay(1000);Serial.print(temp);SerialPrint(".");SerialPrint("BFR=");Serial.print(digitalRead(BFR));SerialPrint("  ");temp++;
}
while (digitalRead(BFR)==1);
Serial.println();
SerialPrintLn("Warm up complete");
 
 DCF.Start();
}

void loop() {
	delay(1000);
	time_t DCFtime = DCF.getTime();
	if (DCFtime!=0) { 
        setTime(DCFtime);
        if (((DCF.DCFminute+2)%3) == 2) {
	SerialPrint("Weather data as DES cipher     : ");	 	  
	for (int j=1;j<43;j++){
		bool p = (DCF.weatherBuffer >> j) & 1;
		Serial.print(p);
	} 
	Serial.println();
 	SerialPrint("Time data from DCF77 raw       : ");
	for (int j=0;j<44;j++){
		bool p = (DCF.keyBuffer >> j) & 1;
		Serial.print(p);
	}
	Serial.println();
          weatherBuffer=0;
	  for (int j=6;j<13;j++){ // minute
            bool signal= ((unsigned long long) ((DCF.keyBuffer>>j) & 1 ) << (j));
	    weatherBuffer = weatherBuffer | ((unsigned long long) signal << j-6);  
	  }
	  for (int j=14;j<20;j++){ // hour
            bool signal= ((unsigned long long) ((DCF.keyBuffer>>j) & 1 ) << (j));
	    weatherBuffer = weatherBuffer | ((unsigned long long) signal << j-6); 
	  }
	  for (int j=21;j<27;j++){ //day
            bool signal= ((unsigned long long) ((DCF.keyBuffer>>j) & 1 ) << (j));
	    weatherBuffer = weatherBuffer | ((unsigned long long) signal << j-5);  
	  }
	  for (int j=30;j<35;j++){ // month
            bool signal= ((unsigned long long) ((DCF.keyBuffer>>j) & 1 ) << (j));
	    weatherBuffer = weatherBuffer | ((unsigned long long) signal << j-6);  
	  }
	  for (int j=27;j<30;j++){ // DOW
            bool signal= ((unsigned long long) ((DCF.keyBuffer>>j) & 1 ) << (j));
	    weatherBuffer = weatherBuffer | ((unsigned long long) signal << j+2);  
	  }
	  for (int j=35;j<43;j++){ // year
            bool signal= ((unsigned long long) ((DCF.keyBuffer>>j) & 1 ) << (j));
	    weatherBuffer = weatherBuffer | ((unsigned long long) signal << j-3);  
	  }
          SerialPrint("Time data formatted as DES key : ");          
	  for (int j=0;j<40;j++){
		bool p = (weatherBuffer >> j) & 1;
		Serial.print(p,DEC);
	  }
          Serial.println();
          decode();
        }
	setTime(DCFtime);digitalClockDisplay(DCFtime);
        if ((DCF.DCFminute)%3 == 0) {SerialPrintLn("***********************************************************************");}
	}	
}

void digitalClockDisplay(time_t _time){
  tmElements_t tm;   
  breakTime(_time, tm);

  SerialPrint("Time: ");
  Serial.print(tm.Hour);
  SerialPrint(":");
  printDigits(tm.Minute);
  SerialPrint(":");
  printDigits(tm.Second);
  SerialPrint(" Date: ");
  Serial.print(tm.Day);
  SerialPrint(".");
  Serial.print(tm.Month);
  SerialPrint(".");
  Serial.println(tm.Year+1970);
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  SerialPrint(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void decode() {
  
//              12345678901234 12345678901234 12345678901234 12345678 12345678 12345678 12345 678 12345678
SerialPrintLn("Datapackage 1  Datapackage 2  Datapackage 3  Time     Hour     Date     month dow year");
for (int k=0;k<82;k++) {

if (k>41) {bool p = (weatherBuffer >> (k-42) & 1);Serial.print(p,DEC);meteobit=p;}
else
{bool p = (DCF.weatherBuffer >>(k+1) &1);Serial.print(p,DEC);meteobit=p;}

digitalWrite (DataIn,meteobit);
digitalWrite (ClockIn, HIGH);
do {}
while (digitalRead (QOut)==LOW);
digitalWrite (ClockIn, LOW);
do {}
while (digitalRead (QOut)==HIGH);
if (k==13 | k==27 | k==41 | k==49 | k==57 | k==65 | k==70 | k==73){SerialPrint(" ");};
}
Serial.println();
do {}
while (digitalRead (QOut)==LOW);
// Collect output data from decoder
bitpattern=0;meteopattern=0;
for (int k=0;k<24;k++){
do {}
while (digitalRead (QOut)==LOW);
meteobit=digitalRead(DataOut);
bitpattern+=meteobit;
bitpattern<<=1;
digitalWrite(ClockIn, HIGH);
do {}
while (digitalRead (QOut)==HIGH);
digitalWrite(ClockIn, LOW);
}
for (int k=1;k<25;k++){
meteobit=(bitpattern>>k)&0x01;
meteopattern+=meteobit;
meteopattern<<=1;
}
SerialPrint("Decoder result   = ");
meteopattern>>=1;
meteodata="";
for (int j=0;j<24;j++){
	bool p = (meteopattern >> j) & 1;
	Serial.print(p,DEC);
        meteodata +=p;
        if ((j+1)%8 == 0) {SerialPrint(" ");}
}
Serial.println();
show();

}

void unbinary(int a, int b){
        val=0;
        for (int i = 0; i < 16; i++) {
        if (! meteodata.substring(a,b) [i]) {
        break;
        }
        val <<= 1;
        val |= (meteodata.substring(a,b) [i] == '1') ? 1 : 0;
        }  
}
void weatherunbinary(int a, int b){
        val=0;
        for (int i = 0; i < 16; i++) {
        if (! weathermemory[fourdayforecast].substring(a,b) [i]) {
        break;
        }
        val <<= 1;
        val |= (weathermemory[fourdayforecast].substring(a,b) [i] == '1') ? 1 : 0;
        }  
}

static int Reverse(int x,int z)
{
y=0;
for (int i = 0; i < z; ++i)
{
y <<= 1;
y |= (x & 1);
x >>= 1;
}
return y;
}

int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

void SerialPrint_P(PGM_P str) {
  for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
}
void SerialPrint_Q(PGM_P str) {
  for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
  Serial.println();
}

void show(){

FLASH_STRING_ARRAY (town,
PSTR("F Bordeaux"), PSTR("F la Rochelle"),PSTR("F Paris"),PSTR("F Brest"),PSTR("F Clermont-Ferrand"),PSTR("F Beziers"),PSTR("B Bruxelles"),PSTR("F Dijon"),PSTR("F Marseille"),PSTR("F Lyon"),PSTR("F Grenoble"),PSTR("CH La Chaux de Fonds"),
PSTR("D Frankfurt am Main"),PSTR("D Trier"),PSTR("D Duisburg"),PSTR("GB Swansea"),PSTR("GB Manchester"),PSTR("F le Havre"),PSTR("GB London"),PSTR("D Bremerhaven"),PSTR("DK Herning"),PSTR("DK Arhus"),PSTR("D Hannover"),PSTR("DK Copenhagen"),PSTR("D Rostock"),
PSTR("D Ingolstadt"),PSTR("D Muenchen"),PSTR("I Bolzano"),PSTR("D Nuernberg"),PSTR("D Leipzig"),PSTR("D Erfurt"),PSTR("CH Lausanne"),PSTR("CH Zuerich"),PSTR("CH Adelboden"),PSTR("CH Sion"),PSTR("CH Glarus"),PSTR("CH Davos"),PSTR("D Kassel"),PSTR("CH Locarno"),PSTR("I Sestriere"),
PSTR("I Milano"),PSTR("I Roma"),PSTR("NL Amsterdam"),PSTR("I Genova"),PSTR("I Venezia"),PSTR("D Strasbourg"),PSTR("A Klagenfurt"),PSTR("A Innsbruck"),PSTR("A Salzburg"),PSTR("A/SK Wien/Bratislava"),PSTR("CZ Praha"),PSTR("CZ Decin"),PSTR("D Berlin"),PSTR("S Gothenburg"),
PSTR("S Stockholm"),PSTR("S Kalmar"),PSTR("S Joenkoeping"),PSTR("D Donaueschingen"),PSTR("N Oslo"),PSTR("D Stuttgart"),
PSTR("I Napoli"),PSTR("I Ancona"),PSTR("I Bari"),PSTR("H Budapest"),PSTR("E Madrid"),PSTR("E Bilbao"),PSTR("I Palermo"),PSTR("E Palma de Mallorca"),
PSTR("E Valencia"),PSTR("E Barcelona"),PSTR("AND Andorra"),PSTR("E Sevilla"),PSTR("P Lissabon"),PSTR("I Sassari"),PSTR("E Gijon"),PSTR("IRL Galway"),PSTR("IRL Dublin"),PSTR("GB Glasgow"),PSTR("N Stavanger"),PSTR("N Trondheim"),PSTR("S Sundsvall"),PSTR("PL Gdansk"),
PSTR("PL Warszawa"),PSTR("PL Krakow"),PSTR("S Umea"),PSTR("S Oestersund"),PSTR("CH Samedan"),PSTR("HR Zagreb"),PSTR("CH Zermatt"), PSTR("HR Split"));  


FLASH_STRING_ARRAY (weather,
PSTR("Reserved"),PSTR("Sunny"),PSTR("Partly clouded"),PSTR("Mostly clouded"),PSTR("Overcast"),PSTR("Heat storms"),PSTR("Heavy rain"),PSTR("Snow"),PSTR("Fog"),PSTR("Sleet"),PSTR("Rain showers"),PSTR("light rain"),
PSTR("Snow showers"),PSTR("Frontal storms"),PSTR("Stratus cloud"),PSTR("Sleet storms")); 

FLASH_STRING_ARRAY (heavyweather,
PSTR("None"),PSTR("Heavy Weather 24 hrs."),PSTR("Heavy weather Day"),PSTR("Heavy weather Night"),PSTR("Storm 24hrs."),PSTR("Storm Day"),PSTR("Storm Night"),
PSTR("Wind gusts Day"),PSTR("Wind gusts Night"),PSTR("Icy rain morning"),PSTR("Icy rain evening"),PSTR("Icy rain night"),PSTR("Fine dust"),PSTR("Ozon"),PSTR("Radiation"),PSTR("High water"));     

FLASH_STRING_ARRAY (probprecip,
PSTR("0 %"),PSTR("15 %"),PSTR("30 %"),PSTR("45 %"),PSTR("60 %"),PSTR("75 %"),PSTR("90 %"),PSTR("100 %"));

FLASH_STRING_ARRAY (winddirection,
PSTR("N"),PSTR("NO"),PSTR("O"),PSTR("SO"),PSTR("S"),PSTR("SW"),PSTR("W"),PSTR("NW"),
PSTR("Changeable"),PSTR("Foen"),PSTR("Biese N/O"),PSTR("Mistral N"),PSTR("Scirocco S"),PSTR("Tramont W"),PSTR("reserved"),PSTR("reserved"));

FLASH_STRING_ARRAY (windstrength,
PSTR("0"),PSTR("0-2"),PSTR("3-4"),PSTR("5-6"),PSTR("7"),PSTR("8"),PSTR("9"),PSTR(">=10"));

FLASH_STRING_ARRAY (anomaly1,
PSTR("Same Weather "),PSTR("Jump 1 "),PSTR("Jump 2 "),PSTR("Jump 3 "));

FLASH_STRING_ARRAY (anomaly2,
PSTR("0-2 hrs"),PSTR("2-4 hrs"),PSTR("5-6 hrs"),PSTR("7-8 hrs"));


        fourdayforecast = ((DCF.DCFhour)%3)*20; if (DCF.DCFminute>0) {fourdayforecast+=(DCF.DCFminute-1)/3;}
        if (DCF.DCFminute>0) {twodayforecast=((((DCF.DCFhour)*60)+(DCF.DCFminute-1))%90)/3;}else{twodayforecast=((DCF.DCFhour)*60);}
        twodayforecast+=60;     
        if (DCF.DCFhour<21) //Between 21:00-23:59 significant weather & temperature is for cities 60-89 wind and wind direction for cities 0-59.
        {
        if ((DCF.DCFhour)%6<3){weathermemory[fourdayforecast]=meteodata;weatherunbinary(8,12);Reverse(val,4);significantweather[fourdayforecast]=y;}// Extreme weather is valid from this hour but also +3 hour  
        Serial.print(fourdayforecast);SerialPrint(" ");town[fourdayforecast].print(Serial);Serial.println(); 
        if (((DCF.DCFhour)%6)>2) {SerialPrint("fourday f/c Night =      ");} else {SerialPrint("fourday f/c Day   =      ");}
        Serial.println((DCF.DCFhour/6)+1);//today is 1 tomorrow 2 etc       
        SerialPrint("Day               =   ");Serial.print(meteodata.substring(0,4));SerialPrint(" "); unbinary(0,4);Reverse (val,4); val=y;Serial.print(val,HEX);SerialPrint(" ");temp=val;
        if (temp==5 || temp==6 || temp==13 || temp==7) {
        if (significantweather[fourdayforecast]==1 || significantweather[fourdayforecast]==2) {if (temp !=6) {Serial.print ("Heavy ");};weather[temp].print(Serial);SerialPrintLn(" with thunderstorms");}
        else {weather[temp].print(Serial);Serial.println();}
        }else{weather[temp].print(Serial);Serial.println();}
        SerialPrint("Night             =   ");Serial.print(meteodata.substring(4,8));SerialPrint(" "); unbinary(4,8); Reverse (val,4);val=y;Serial.print(val,HEX);SerialPrint(" ");temp=val;
        if (temp==5 || temp==6 || temp==13 || temp==7) {
        if (significantweather[fourdayforecast]==1 || significantweather[fourdayforecast]==3) {if (temp !=6) {Serial.print ("Heavy ");};weather[temp].print(Serial);SerialPrintLn(" with thunderstorms");}
        else {weather[temp].print(Serial);Serial.println();}
        }else {if (temp==1) {SerialPrint("Clear");;Serial.println();} else {weather[temp].print(Serial);Serial.println();}
        }
        if ((DCF.DCFhour)%6<3){
        SerialPrint("Rainprobability   =    ");Serial.print(meteodata.substring(12,15));SerialPrint(" "); unbinary(12,15);Reverse (val,3);val=y;
        Serial.print(val,HEX);SerialPrint(" ");probprecip[val].print(Serial); Serial.println();
        SerialPrint("Extremeweather    =   "); unbinary(15,16);
        if (val==0) {// DI=0 and WA =0
        Serial.print(weathermemory[fourdayforecast].substring(8,12));SerialPrint(" ");
        Serial.print(significantweather[fourdayforecast],HEX);SerialPrint(" ");heavyweather[significantweather[fourdayforecast]].print(Serial); Serial.println();
        } else {
        Serial.print(meteodata.substring(8,10));SerialPrint(" ");  
        unbinary(8,10);Serial.print(val,HEX);SerialPrint(" ");anomaly1[val].print(Serial); Serial.println();
        SerialPrint("                  =     ");
        Serial.print(meteodata.substring(10,12));SerialPrint(" ");
        unbinary(10,12);Serial.print(val,HEX);SerialPrint(" ");anomaly2[val].print(Serial); Serial.println(); 
        }          
        }
        if ((DCF.DCFhour)%6>2){        
        SerialPrint("Winddirection     =   ");Serial.print(meteodata.substring(8,12));SerialPrint(" ");unbinary(8,12);Reverse (val,4);val=y;
        Serial.print(val,HEX);SerialPrint(" ");winddirection[val].print(Serial); Serial.println();
        SerialPrint("Windstrength      =    ");Serial.print(meteodata.substring(12,15));SerialPrint(" ");unbinary(12,15);Reverse (val,3);val=y;
        Serial.print(val,HEX);SerialPrint(" ");windstrength[val].print(Serial); SerialPrintLn(" Bft");
        SerialPrint("Extremeweather    =   ");
        Serial.print(weathermemory[fourdayforecast].substring(8,12));SerialPrint(" ");
        Serial.print(significantweather[fourdayforecast],HEX);SerialPrint(" ");heavyweather[significantweather[fourdayforecast]].print(Serial); Serial.println();       
        } 
        SerialPrint("Weather Anomality =      ");Serial.print(meteodata.substring(15,16));SerialPrint(" "); unbinary(15,16);Serial.print(val,HEX);
        if (val==1) {SerialPrintLn(" Yes");} else {SerialPrintLn(" No");}
        }
        else
        //*********************************************************************************************************************************
        {
        Serial.print(fourdayforecast);SerialPrint(" ");town[fourdayforecast].print(Serial);Serial.println(); 
        if (((DCF.DCFhour)%6)>2) {SerialPrint("fourday f/c Night =      ");} else {SerialPrint("fourday f/c Day   =      ");}
        Serial.println((DCF.DCFhour/6)+1);//today is 1 tomorrow 2 etc        
        SerialPrint("Winddirection     =   ");Serial.print(meteodata.substring(8,12));SerialPrint(" ");unbinary(8,12);Reverse (val,4);val=y;
        Serial.print(val,HEX);SerialPrint(" ");winddirection[val].print(Serial); Serial.println();
        SerialPrint("Windstrength      =    ");Serial.print(meteodata.substring(12,15));SerialPrint(" ");unbinary(12,15);Reverse (val,3);val=y;
        Serial.print(val,HEX);SerialPrint(" ");windstrength[val].print(Serial); SerialPrintLn(" Bft");
        Serial.print(twodayforecast);SerialPrint(" ");town[twodayforecast].print(Serial);Serial.println();  
        SerialPrint("twoday f/c day    =      ");
        if (((DCF.DCFhour-21)*60+DCF.DCFminute)>90) {SerialPrintLn("2");}else{SerialPrintLn("1");}//today is 1 tomorrow 2 etc                
        SerialPrint("Day               =   ");Serial.print(meteodata.substring(0,4));SerialPrint(" "); unbinary(0,4);Reverse (val,4); val=y;Serial.print(val,HEX);SerialPrint(" ");
        temp=val; unbinary(8,12); Reverse (val,4);val=y;
        weather[temp].print(Serial);Serial.println();
        SerialPrint("Night             =   ");Serial.print(meteodata.substring(4,8));SerialPrint(" "); unbinary(4,8); Reverse (val,4);val=y;Serial.print(val,HEX);SerialPrint(" ");
        if (val==1) {SerialPrint("Clear");;Serial.println();} else {weather[temp].print(Serial);Serial.println();}
        SerialPrint("Weather Anomality =      ");Serial.print(meteodata.substring(15,16));SerialPrint(" "); unbinary(15,16);Serial.print(val,HEX);
        if (val==1) {SerialPrintLn(" Yes");} else {SerialPrintLn(" No");}      
        }
        SerialPrint("Temperature       = ");Serial.print(meteodata.substring(16,22));SerialPrint(" "); unbinary(16,22);Reverse (val,6);val=y;    
        SerialPrint("0x");Serial.print(val,HEX);SerialPrint(" ");
        if (val==0) {SerialPrint("<-21 ");Serial.print(char(176));SerialPrint("C");}
        if (val==63) { Serial.print (">40 ");Serial.print(char(176));SerialPrint("C");}
        if ((val!=0) & (val!=63)) {Serial.print(val-22,DEC);Serial.print(char(176));SerialPrint("C");} 
        // Night temperature is minimum
        // Daytime temperature is daytime maximum       
        if (((DCF.DCFhour)%6)>2 && (DCF.DCFhour<21)) {SerialPrintLn(" minimum");} else {SerialPrintLn(" maximum");}        
        SerialPrint("Decoder status    =     "); 
        Serial.print(meteodata.substring(22,24));
        if(meteodata.substring(22,24) == "10") {Serial.println (" OK");} else {Serial.println (" NOT OK");} 
}



Here is an example of the output of this program. You can see how the data is collected from the DCF77 output and assembled into the DES cypher and DES key. It is then clocked into the HKW581 and the result is translated into human readible form.

meteotime output

Below you can see a map showing the region numbers throughout Europe.

DCF weather regions

 

 

 

 

 

 

I have made a HKW581 DCF77 receiver shield for arduino.
The design can use most DCF77 receivers from many brands but i recommend the EM15 receiver module from HKW which is a three frequency board. It will however be wired for  77.5 and 60.0 kHz so that it is possible to receive both DCF77 and the MSF time signals. The board will fit onto the 8 pins at the extreme left of the home weather station shield. All the pins are prewired so there is no connecting to do.
The boards have been ordered and i will put them in the shop when they arrive.

Please click on schematic or PCB image to get a larger view.

HKW581 shield sch

HKW581 shield pcb

 

 

 

 

 

 

 

 

 

Below you can see the jumper connections depending on which board you are wiring to.
Most boards are supported

HKW EM6 3V Empfangsmodul-EM6-77-5-kHz-3V
HKW EM2S Empfangsmodul-EM2S-DCF
Conrad 641138
Pollin 810054
Reichelt DCF77 MODUL
ELV 68-09 16 10

 

 

 

HKW581 jumper

You can find out a bit more about the Meteotime signal and decoding it using only an arduino here.
If you are still wanting to build a DCF77 receiver look here.

5 comments

  1. dl1eem says: January 28, 2017
  2. ivo.colle says: August 22, 2016

Trackbacks and pingbacks

No trackback or pingback available for this article

Leave a Reply