Translate

Friday 12 December 2014

Arduino Dehumidifier Controller Failure, and Upgrade!

The dehumidifier controller has been performing faultlessly throughout the summer months. And I've done the geeky thing and plotted the data out on a month by month basis. Humidity has been relatively steady...


Every month has seen the odd un-explainable spike, but other than that it's all been good.

Now the weather has gone colder, I'm a bit concerned about the state of things up there in the attic, but have been keeping an eye on it, and it's been dry, until last week, when there was signs of condensation. I started to contemplate moving the switch point in the sketch to bring the dehumidifier on a little earlier, especially as the actual roof will be cooler than the surrounding air. And also maybe a loop which runs the dehumidifier for an hour every now-and-again, just to make sure it's still working OK (it didn't run for months during the summer).

Also, one months data is 3GB ! Which takes Open Office Calc a little while to plot (like hours), so I thought about slowing the transmission rate down again. Anyway, most of this was a little way down the list of things to do... until Monday, when the kitchen display shows the following....



Now, it's a few degrees above freezing outside, and there's no way it's a balmy 60 in my attic, unless it's on fire.

I go into the attic and reset the box. Nope, same lies there.

I bring the box downstairs and do a few checks. 5v is nice and steady. I re-load the sketch and libraries. No, still the same. I load a simple test sketch provided with the library, and the same lies are repeated via the serial monitor.

So, it's most likely the DHT11 itself has a screw-loose, and has fond memories for hot summer's days!

I think this is a good opportunity to re-engineer the sketch slightly, and have a play with oh-so-very nice DHT22.



Now the DHT22 (A.K.A. RHT03 or  AM2302) has almost the same form factor as the DHT11, is catered for by our library, has the same pinouts, and has better accuracy and does a wider range of temperature (goes negative too) and humidity. It's a little bit more expensive.

I also decide to decrease the transmission rate to one every 198 seconds, and to bring the dehumidifier on when the dew point is within 10 degrees of the temperature. Also, regardless of temperature or humidity, the dehumidifer is run once every 259,200 seconds (or 3 days) just to keep the dehumidifier running and humidity low.

 Sensible figures now...



... and negative if it gets cold up there!









Here's the sketch:


// Wireless dehumidifier Controller
// 
// Copyright Andy Doswell 24th May 2014 modified Dec 2014
// PURPOSE: DHT22 sensor with LCD Display and output for controlling dehumidifier.
// Data send via virtualwire and 433MHZ link to remote display
// Dehumidifier is controlled by a relay attached to pin 7, defined in rlyPin.
// DHT22 sensor is connected to 8, as defined in #define
// LCD is a Hitachi HD44780 or compatible, attached thus:
// LCD RS pin to digital pin 12
// LCD Enable pin to digital pin 11
// LCD D4 pin to digital pin 5
// LCD D5 pin to digital pin 4
// LCD D6 pin to digital pin 3
// LCD D7 pin to digital pin 2
// RW to GND
// V0 Held high (this may or may not work with your LCD, usual practice is to connect this to a 10K pot between +5 and GND)
// TX connected to pin 10
// Modified to transmit every 198 seconds, and to switch dehumidifier on when Dewpoint is within 10 Degrees of actual temperature
// Also brings dehumidifer on every 3 days regardless of temperature or humidity.
// You'll need the wonderful dht library by Rob Tillaart from here : https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib 
// and the equally wonderful Virtualwire library from here :https://www.pjrc.com/teensy/td_libs_VirtualWire.html


// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
 double a = 17.271;
 double b = 237.7;
 double temp = (a * celsius) / (b + celsius) + log(humidity*0.01);
 double Td = (b * temp) / (a - temp);
 return Td;
}

#include <VirtualWire.h>
#include <VirtualWire_Config.h>

#include <dht.h>


dht DHT;

#define DHT22_PIN 8

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// define constants & global variables
const int rlyPin = 7; //defines pin the relay is connected to. relay is active low
const int TimerLength = 1800;// number of seconds in an hour / 2 - this sets the minimum time the dehumidifier will remain on for.
int Timer = 0; //timer is off to start
boolean DewFlag = false; // This is the dew flag. Off as default.
boolean OutputStatus = false; //Output status is off as default
int chk;
int Temp;
int Dew;
int Humidity;
int DewTrip;
float Timer2 = 0;


// Data structure set up for Transmission

struct TXData
{
  int TX_ID;
  int Temp;
  int Humidity;
  int Dew;
  boolean Output;
};
  

void setup()
{
  lcd.begin(16, 2); // defines the LCD as a 16 x 2
  pinMode (rlyPin, OUTPUT); // sets our relay pin
  digitalWrite (rlyPin, HIGH); // sets the relay off for default condition.
  
  // Virtualwire setup
  vw_set_tx_pin(10); // TX pin set to 10
  vw_set_rx_pin(9); // RX pin set to a spare pin, even though we don't use it. If left as default it interferes with LCD operation.
  vw_setup(300); //sets virtualwire for a tx rate of 300 bits per second
  

}

void loop()
{
  for(int i = 0; i < 100 ; i++) { //transmit only every 99 loops (198 seconds)
    chk = DHT.read22(DHT22_PIN); // these 4 lines get data from the sensor
    Dew = dewPointFast(DHT.temperature, DHT.humidity);
    Temp = (DHT.temperature);
    Humidity = (DHT.humidity);
    DewTrip= Dew + 10; // Brings the dehumidifier on 5 deg C before the dew point. 
  
    // writes information about the system to the LCD
    lcd.clear ();
    lcd.print("Humidity:");
    lcd.print(Humidity);
    lcd.print("%");
    lcd.setCursor(0, 1);
    lcd.print(Temp);
    lcd.print((char)0xDF);
    lcd.print("C");
    lcd.setCursor(6, 1);
    lcd.print("Dew:");
    lcd.print(Dew);
    lcd.print((char)0xDF);
    lcd.print("C");
   
  // Dew detect loop. If the dewTrip point is reached, start the timer running and set the Dew flag
    if ( Temp <= DewTrip || Timer2 == 129600 ) {
      DewFlag = true;
      Timer = 1;    
      Timer2 = 0;   
    } 
    else {
      DewFlag = false;
    }

  
    if (Timer >= TimerLength and DewFlag == false) { // If the timer has expired and there's no dew, switch the dehumidifier off.
      Timer = 0;
      digitalWrite (rlyPin, HIGH);
   
    }

    if (Timer !=0) {                // If the timer is running, switch the dehumidifier on , and write On to the lcd.
      digitalWrite (rlyPin, LOW);
      lcd.setCursor (13,0);
      lcd.print (" On");
      OutputStatus = true;
      Timer++;
    }
  
    else {
      lcd.setCursor (13,0);
      lcd.print ("off");
      OutputStatus = false;
    }
  
 delay (2000);
 Timer2 ++;
  }
  


  
struct TXData payload; //Loads the Data struct with the payload data
lcd.clear ();
lcd.print ("Transmitting");
  
payload.TX_ID=10;
payload.Temp = Temp;
payload.Humidity = Humidity;
payload.Dew = Dew;
payload.Output = OutputStatus;
vw_send((uint8_t *)&payload, sizeof(payload)); //Transmits the struct
vw_wait_tx(); //waits for the TX to complete

}  
  


Friday 5 December 2014

Arduino astronomical clock pond pump controller (now with added frost protection)

Time to revisit a project from August...

It's December, the weather forecast for this weekend looks cold.

"What happens if the pond freezes"? asks the wife.

Ugh! I hadn't though of that when I originally came up with the pond pump controller.

In my installation it will be the weir that freezes first, the pump will probably be OK, but empty the pond as the weir will spill over where it's not wanted... so what we need is temperature protection.

Now we've looked at measuring temperature and humidity before here, but this time we need to be measuring low temperatures. Now the DHT11 is a fine device, but it won't go negative, so is unsuitable.

Enter the Maxim (formerly Dallas) DS18B20 IC. Looks like a small transistor (TO-92) package when naked. Find the data here.

Terrific little guy, communicates on a one-wire interface, and is dirt cheap.

I chose an encapsulated temperature probe type from eBay, change from £2!

Superb.

First problem is it doesn't say which wires are which. Mine came with red, green and yellow wires.

Red is +5V Yellow is GND and Green is data.

Marvellous, sealed and a lead long enough to go out through the hole in the wall.

Now we'll need a couple of libraries, and the lovely people at hacktonics have produced a great guide, which I suggest you take a few minutes to read.  http://www.hacktronics.com/Tutorials/arduino-digital-temperature-sensor-tutorial.html

OK, so we'll cobble up our sensor to a spare Arduino, data to pin 3, and a 4.7 Kohm pull up from there to +5 volts.

We'll need to find out the address for our sensor. The beauty of this system is we can hang many sensors off our one wire. We only need one, but we'll still need to find it's address.

Go here: http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.htm and get the one wire library, the dallas library and the address finder sketch. Load the whole shebang into the IDE. I had issues getting the DallasTemperature library to install. Just make sure the .h and .cpp files are in the top directory, and not hidden one down, otherwise the IDE won't find them.

Once you've got that running, open a serial monitor, and the sketch should provide you with the address. In my example it was 0x28, 0x1A, 0x1A, 0x3E, 0x06, 0x00, 0x00,0xC7 write your address down, as you'll need to enter it into the sketch.

Load up the sketch from below, and wire your sensor to +5v and GND, but this time the pull up and data wire to pin 8 (we used pin 3 for the encoder)

I've moved the display around a bit to accommodate temperature display, and there's a minor change to the way the screen is refreshed after returning from a subroutine, to prevent old data being retained on the display. Of course now the output will only be on when the sun's up AND it's not freezing!


Here's the sketch....




// Dawn & Dusk controller with frost protection.
// 5th December 2014.
// (C) A.G.Doswell 2014
//
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
//
// Designed to control a relay connected to pin A3. Pin goes low during daylight hours and high during night. Relay uses active low, so is
// "On" during the day. This is connected to the fountain pump in my garden.
//
// Time is set using a rotary encoder with integral push button. The Encoder is connected to interrupt pins D2 & D3 (and GND), 
// and the push button to pin analogue 0 (and GND)
// The RTC is connections are: Analogue pin 4 to SDA. Connect analogue pin 5 to SCL.
// A 2 x 16 LCD display is connected as follows (NOTE. This is NOT conventional, as interrupt pins are required for the encoder)
//  Arduino LCD  
//  D4      DB7
//  D5      DB6
//  D6      DB5
//  D7      DB4
//  D12     RS
//  D13     E
// 
// In this revision, there is a Dallas 18B20 Temperature sensor connected to pin 8, enabling frost protection. This is pulled up to +5volts via a 470K resistor.
//
// Use: Pressing and holding the button will enter the clock set mode (on release of the button). Clock is set using the rotary encoder. 
// The clock must be set to UTC.
// Pressing and releasing the button quickly will display the current sun rise and sun set times. Pressing the button again will enter the mode select menu. 
// Modes are AUTO: On when the sun rises, off when it sets.
//           ON: Permanently ON
//           OFF: Permanently OFF (Who'd have guessed it?)
//
// Change the LATTITUDE and LONGITUDE constant to your location.
// Use the address finder from http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html to find the address of your temperature sensor and enter it where required in DeviceAddress.
// 
// Be sure to visit my website at http://andydoz.blogspot.com

#include <Wire.h>
#include "RTClib.h" // from https://github.com/adafruit/RTClib
#include <LiquidCrystal.h>
#include <Encoder.h> // from http://www.pjrc.com/teensy/td_libs_Encoder.html
#include <TimeLord.h> // from http://swfltek.com/arduino/timelord.html. When adding it to your IDE, rename the file, removing the "-depreciated" 
#include <OneWire.h> // from http://playground.arduino.cc/Learning/OneWire
#include <DallasTemperature.h> // from http://www.hacktronics.com/code/DallasTemperature.zip. When adding this to your IDE, ensure the .h and .cpp files are in the top directory of the library.


#define ONE_WIRE_BUS 8 // Data wire from temp sensor is plugged into pin 8 on the Arduino
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices
DeviceAddress outsideThermometer = { 0x28, 0x1A, 0x1A, 0x3E, 0x06, 0x00, 0x00,0xC7 }; // use the address finder from http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html to find the address of your device.
RTC_DS1307 RTC; // Tells the RTC library that we're using a DS1307 RTC
Encoder knob(2, 3); //encoder connected to pins 2 and 3 (and ground)
LiquidCrystal lcd(12, 13, 7, 6, 5, 4); // I used an odd pin combination because I need pin 2 and 3 for the interrupts.
//the variables provide the holding values for the set clock routine
int setyeartemp; 
int setmonthtemp;
int setdaytemp;
int sethourstemp;
int setminstemp;
int setsecs = 0;
int maxday; // maximum number of days in the given month
int TimeMins; // number of seconds since midnight
int TimerMode = 2; //mode 0=Off 1=On 2=Auto
int TimeOut = 10;
int TimeOutCounter;

// These variables are for the push button routine
int buttonstate = 0; //flag to see if the button has been pressed, used internal on the subroutine only
int pushlengthset = 3000; // value for a long push in mS
int pushlength = pushlengthset; // set default pushlength
int pushstart = 0;// sets default push value for the button going low
int pushstop = 0;// sets the default value for when the button goes back high

int knobval; // value for the rotation of the knob
boolean buttonflag = false; // default value for the button flag
float tempC; // Temperature


const int TIMEZONE = 0; //UTC
const float LATITUDE = 51.89, LONGITUDE = -2.04; // set YOUR position here 
int Sunrise, Sunset; //sunrise and sunset expressed as minute of day (0-1439)
TimeLord myLord; // TimeLord Object, Global variable
byte sunTime[]  = {0, 0, 0, 1, 1, 13}; // 17 Oct 2013
int SunriseHour, SunriseMin, SunsetHour, SunsetMin; //Variables used to make a decent display of our sunset and sunrise time.
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature.

void setup () {
    //Serial.begin(57600); //start debug serial interface
    Wire.begin(); //start I2C interface
    RTC.begin(); //start RTC interface
    lcd.begin(16,2); //Start LCD (defined as 16 x 2 characters)
    lcd.clear(); 
    pinMode(A0,INPUT);//push button on encoder connected to A0 (and GND)
    digitalWrite(A0,HIGH); //Pull A0 high
    pinMode(A3,OUTPUT); //Relay connected to A3
    digitalWrite (A3, HIGH); //sets relay off (default condition)
    sensors.begin();
    sensors.setResolution(outsideThermometer, 12); // set the resolution to 12 bits (why not?!)
    
    //Checks to see if the RTC is runnning, and if not, sets the time to the time this sketch was compiled.
    if (! RTC.isrunning()) {
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
 
 
    //Timelord initialisation
    myLord.TimeZone(TIMEZONE * 60);
    myLord.Position(LATITUDE, LONGITUDE);
    CalcSun ();
}
           
void printTemperature(DeviceAddress deviceAddress)
{
  lcd.setCursor (9,1);
  tempC = sensors.getTempC(deviceAddress);
  if (tempC == -127.00) {
    Serial.print("Err");
  } else {
    
    lcd.print(tempC);
    lcd.print((char)0xDF);
    lcd.print("C ");
   
  }
}

void loop () {
    sensors.requestTemperatures(); // Request temperature
    printTemperature(outsideThermometer); // display on lcd.
    DateTime now = RTC.now(); //get time from RTC
    //Display current time
    lcd.setCursor (0,0);
    lcd.print(now.day(), DEC);
    lcd.print('/');
    lcd.print(now.month());
    lcd.print('/');
    lcd.print(now.year(), DEC);
    lcd.print(" ");
    lcd.setCursor (0,1);
    lcd.print(now.hour(), DEC);
    lcd.print(':');
    if (now.minute() <10) 
      {
        lcd.print("0");
      }
    lcd.print(now.minute(), DEC);
    lcd.print(':');
    if (now.second() <10) 
      {
        lcd.print("0");
      }
    lcd.print(now.second());
    lcd.print(" ");
    
    //current time in minutes since midnight (used to check against sunrise/sunset easily)
    TimeMins = (now.hour() * 60) + now.minute();
    
    // Calculate sun times once a day at a minute past midnight
    if (TimeMins == 1) {
      CalcSun ();
    }
    if (TimerMode ==2) {
      if (TimeMins >= Sunrise && TimeMins <=Sunset-1 && tempC>=1) { //If it's after sunrise and before sunset, and it's not frozen, switch our relay on
          digitalWrite (A3, LOW);
          lcd.setCursor (13,0);
          lcd.print ("On ");
        }
        else {  //otherwise switch it off
          digitalWrite (A3, HIGH);
          lcd.setCursor (13,0);
          lcd.print ("Off");
        }
      }
       if (TimerMode ==0) {
         digitalWrite (A3, HIGH);
         lcd.setCursor (13,0);
         lcd.print ("Off");
       }
     
       if (TimerMode ==1) {
         digitalWrite (A3, LOW);
         lcd.setCursor (13,0);
         lcd.print ("On ");
       }
       
       sensors.requestTemperatures(); // Request temperature
       printTemperature(outsideThermometer); // display on lcd.
    
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    delay (10);
    
    if (pushlength <pushlengthset) {
      lcd.clear ();
      ShortPush ();   
      lcd.clear ();
    }
    
       
       //This runs the setclock routine if the knob is pushed for a long time
       if (pushlength >pushlengthset) {
         lcd.clear();
         DateTime now = RTC.now();
         setyeartemp=now.year(),DEC;
         setmonthtemp=now.month(),DEC;
         setdaytemp=now.day(),DEC;
         sethourstemp=now.hour(),DEC;
         setminstemp=now.minute(),DEC;
         setclock();
         pushlength = pushlengthset;
       };
}

//sets the clock
void setclock (){
   setyear ();
   lcd.clear ();
   setmonth ();
   lcd.clear ();
   setday ();
   lcd.clear ();
   sethours ();
   lcd.clear ();
   setmins ();
   lcd.clear();
   RTC.adjust(DateTime(setyeartemp,setmonthtemp,setdaytemp,sethourstemp,setminstemp,setsecs)); //set the DS1307 RTC
   CalcSun (); //refresh the sunrise and sunset times
   delay (1000);
   
}

// subroutine to return the length of the button push.
int getpushlength () {
  buttonstate = digitalRead(A0);  
       if(buttonstate == LOW && buttonflag==false) {     
              pushstart = millis();
              buttonflag = true;
          };
          
       if (buttonstate == HIGH && buttonflag==true) {
         pushstop = millis ();
         pushlength = pushstop - pushstart;
         buttonflag = false;
       };
       return pushlength;
}
// The following subroutines set the individual clock parameters
int setyear () {
   lcd.setCursor (0,0);
    lcd.print ("Set Year");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return setyeartemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) { //bit of software de-bounce
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    setyeartemp=setyeartemp + knobval;
    if (setyeartemp < 2014) { //Year can't be older than currently, it's not a time machine.
      setyeartemp = 2014;
    }
    lcd.print (setyeartemp);
    lcd.print("  "); 
    setyear();
}
  
int setmonth () {

   lcd.setCursor (0,0);
    lcd.print ("Set Month");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return setmonthtemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    setmonthtemp=setmonthtemp + knobval;
    if (setmonthtemp < 1) {// month must be between 1 and 12
      setmonthtemp = 1;
    }
    if (setmonthtemp > 12) {
      setmonthtemp=12;
    }
    lcd.print (setmonthtemp);
    lcd.print("  "); 
    setmonth();
}

int setday () {
  if (setmonthtemp == 4 || setmonthtemp == 5 || setmonthtemp == 9 || setmonthtemp == 11) { //30 days hath September, April June and November
    maxday = 30;
  }
  else {
  maxday = 31; //... all the others have 31
  }
  if (setmonthtemp ==2 && setyeartemp % 4 ==0) { //... Except February alone, and that has 28 days clear, and 29 in a leap year.
    maxday = 29;
  }
  if (setmonthtemp ==2 && setyeartemp % 4 !=0) {
    maxday = 28;
  }
  
   lcd.setCursor (0,0);
    lcd.print ("Set Day");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return setdaytemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    setdaytemp=setdaytemp+ knobval;
    if (setdaytemp < 1) {
      setdaytemp = 1;
    }
    if (setdaytemp > maxday) {
      setdaytemp = maxday;
    }
    lcd.print (setdaytemp);
    lcd.print("  "); 
    setday();
}

int sethours () {
    lcd.setCursor (0,0);
    lcd.print ("Set Hours");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return sethourstemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    sethourstemp=sethourstemp + knobval;
    if (sethourstemp < 1) {
      sethourstemp = 1;
    }
    if (sethourstemp > 23) {
      sethourstemp=23;
    }
    lcd.print (sethourstemp);
    lcd.print("  "); 
    sethours();
}

int setmins () {

   lcd.setCursor (0,0);
    lcd.print ("Set Mins");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return setminstemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    setminstemp=setminstemp + knobval;
    if (setminstemp < 0) {
      setminstemp = 0;
    }
    if (setminstemp > 59) {
      setminstemp=59;
    }
    lcd.print (setminstemp);
    lcd.print("  "); 
    setmins();
}

int setmode () { //Sets the mode of the timer. Auto, On or Off

    lcd.setCursor (0,0);
    lcd.print ("Set Mode");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return TimerMode;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    TimerMode=TimerMode + knobval;
    if (TimerMode < 0) {
      TimerMode = 0;
    }
    if (TimerMode > 2) {
      TimerMode=2;
    }
    if (TimerMode == 0) {
    lcd.print("Off");
    lcd.print("  "); 
    }
    if (TimerMode == 1) {
    lcd.print("On");
    lcd.print("  "); 
    }
    if (TimerMode == 2) {
    lcd.print("Auto");
    lcd.print("  "); 
    }
    setmode ();
}

int CalcSun () { //Calculates the Sunrise and Sunset times
    DateTime now = RTC.now();
    sunTime[3] = now.day(); // Give Timelord the current date
    sunTime[4] = now.month();
    sunTime[5] = now.year();
    myLord.SunRise(sunTime); // Computes Sun Rise.
    Sunrise = sunTime[2] * 60 + sunTime[1]; // Sunrise returned in minutes past midnight
    SunriseHour = sunTime[2];
    SunriseMin = sunTime [1];
    sunTime[3] = now.day(); // Uses the Time library to give Timelord the current date
    sunTime[4] = now.month();
    sunTime[5] = now.year();
    myLord.SunSet(sunTime); // Computes Sun Set.
    Sunset = sunTime[2] * 60 + sunTime[1]; // Sunset returned in minutes past midnight
    SunsetHour = sunTime[2];
    SunsetMin = sunTime [1];
}

void ShortPush () {
  //This displays the calculated sunrise and sunset times when the knob is pushed for a short time.
for (long Counter = 0; Counter < 604 ; Counter ++) { //returns to the main loop if it's been run 604 times 
                                                     //(don't ask me why I've set 604,it seemed like a good number)
  lcd.setCursor (0,0);
  lcd.print ("Sunrise ");
  lcd.print (SunriseHour);
  lcd.print (":");
  if (SunriseMin <10) 
     {
     lcd.print("0");
     }
  lcd.print (SunriseMin);
  lcd.setCursor (0,1);
  lcd.print ("Sunset ");
  lcd.print (SunsetHour);
  lcd.print (":"); 
    if (SunsetMin <10) 
     {
     lcd.print("0");
     }
  lcd.print (SunsetMin);        

    
  //If the knob is pushed again, enter the mode set menu
  pushlength = pushlengthset;
  pushlength = getpushlength ();
  if (pushlength != pushlengthset) {
    lcd.clear ();
    TimerMode = setmode ();

  }
  
}



}
  
 

Saturday 15 November 2014

Mitsubishi HS-M60V repair.



The venerable workshop VHS machine has finally given up after many years of sterling service. It doesn't make it into play or record. It'll be the loading belt, a small, rubber drive belt that's used to move the components of the mechanism into it's various modes. Why do I want to repair it? Because:
1) I can.
2) It's better repaired than in landfill. I hate to see stuff thrown out.
3) Because this machine is very good at recording and playing back system A video.

Thankfully a new belt kit is obtained from the lovely people at www.notobsolete.co.uk

As per usual, unplug the machine from the mains. Don't argue, do it.

There are two screws on the left and right sides of the top cover. Undo them and remove the top.

Grasp the joggly shuttler thing, and pull it off.











There.... put it safely to one side.
Undo the plastic catches holding the front panel on. Three on the top, two on the sides....








... and three across the bottom....
With a bit of jiggling, the front panel will now come off.



















Put the machine on it's side.
Remove the three screws,. indicated with arrows stamped into the base plate, I've circled them in the photo.  Put the machine back on it's feet.

















We now need to remove the deck. It's held in with 5 screws...









Two down the holes conveniently positioned on the cassette housing (the bit that loads the cassette onto the deck)



One to the rear right hand side of the deck...









One on the rear left...











... and one in the middle by the head amplifier.


While you're there, unplug the cable to the top of the head amplifier....

 ... and the one to the right of the cassette housing, which connects the end sensor..










You should now be able to remove the deck from the main board and case etc ... Just grab it by the cassette housing and gently pull...










Flip the deck over....

The big belt from the capstan motor to the reel drive gear is easy to get at, so replace it now, whilst we've got the machine apart.


The loading belt is located as shown by the arrow in the picture to the right. The shaft that the belt drives (the bit with the little fan on) is only held in position by the force of the belt and a small black plastic clip. Now we could disassemble the entire loading gear and gain easy access to the motor, belt and shaft, but then be faced with a re-alignment job... nah. Careful use of some small, needle nose pliers, and the belt can be worked out from around the shaft!

... and there's some access to the loading motor spindle from the top of the deck too...










The old loading belt had lost it's tension, and wasn't exactly round anymore....








Fit the new belt, Reassemble the machine, making sure to reconnect the end sensor cable, and supply to the head amp. When refitting the deck, check the large multipin connectors under the head amp have located and seated correctly. Test for correct operation. Have a cup of tea safe in the knowledge of a job well done, and another piece of kit saved from landfill! 

Friday 31 October 2014

Meade EXT105 Telescope repair.

A while ago a friend contacted me with regards to a Meade telescope that belonged to a colleague of his. Time elapsed, and eventually it made it's way into the workshop.

This is some bit of kit. Now I'm no star-gazer (although I've always fancied the idea) but this thing looks fantastic. Once calibrated, you can search it's database and set it to automatically point in the right direction of the celestial body you wish to view. Brilliant..... except for this one, which threw a fit when asked to point to something, and smoke bilged out from the motor that makes it move up and down (I would say it's an EL or elevation motor, but apparently when dealing with telescopes, it's a DEC or declination motor, lord knows why).



Beast of a thing. First challenge was to get the optics out and placed to one side, out of harm's way... Two cap screws this side, and two the other hold the complete optics onto the base. It takes some gentle persuasion to extract them. 
There's some sort of electronics attached to the top of the optics ( not really sure of their purpose! Let me know! ) . This board and it's cover are held in place by a single cap screw. There's a 4 pin connector to undo to release it.



Once the optics are out we can disassemble the stand. Removing the cover off the motor for the DEC drive, reveals some damage!









Ugh... 
Unidentifiable burned-out IC's ...

We must never forget that electronics is driven by high-pressure smoke. You can see here where the failure has been caused by the smoke escaping from the IC's.

Emailing Meade and a few of their dealers gets me nowhere. Not even a reply. Thanks guys.


It does, however dawn on me, that the circuit that drives the Azimuth motor may be the same...



..and on closer inspection, it is certainly similar. The components are in a different position, but the circuit appears the same. 

By a process of elimination, the bits we need are a SI4947ADY & SI4936CDY. eBay is our friend. 

Each of these IC's house two MOSFETs. The SI4947ADY is P-channel and the SI4936CDY N-channel.


Having identified the parts, we give ourselves another problem! Which is which....

Having a careful look at the remains under a lupe, one IC gives us a clue, the SI4936CDY is on the left, the SI4947ADY in the middle (It's a 7805 voltage regulator on the right)



The old components are removed, and the board cleaned up. There's some damage to the print under the SI4947ADY in the middle. I have to add a tiny piece of wire here to make up the pad, and attempt to fit the IC on the top....





New IC's are fitted. I check for shorts & open circuit connections. It all checks out OK. The tiny wire under pin 1 is good to go!














 I decide to add a 0.01uF capacitor across the motor terminals to try and protect the electronics a little more from the spikes coming from the motor. I wouldn't mind betting this is what damaged the electronics in the first place.




... and then the daunting task of re-assembly. Nothing really to note here, other than be careful to route the wiring through the DEC motor board which connects to "the mystery electronics" on the top of the optics!

And then , bullet firmly between teeth.... Power-up!














  

WEM Watkins Copicat, repairs, renovations and electrical safety upgrades!

Minding my own business, when the telephone goes, and it's a friend with a wobbly Watkins that no longer works.


Cabinet's OK. Shabby chic. Hinges need replacing...
Obviously heavily gigged in smokey pubs! Tape path is dirty, and the heads are worn, but they'll go for a while yet.








Most of the caps in the supply are in poor condition. These two were replced, the originals being high ESR and low capacity. There were also two caps decoupling the +/- 12 volts rails. One was short circuit.
One of the main problems with the copicat, is it's lack-luster electrical safety. It was made back-in-the-day when standards were different. There's a nice metal box, the chassis of which is used to ground the audio incoming and outgoing. Now here's the issue. It's not grounded to a safety electrical earth. There's only a 2 core mains lead fitted. Now in this day and age , this isn't good enough. Not unless special precautions are taken (double insulated). This certainly isn't double insulated, and, although a remote possibility, if a live wire were to come off the motor or mains transformer, and connect with the metal chassis, the ground of your guitar would now be live. It's going to hurt, or kill. Not good. It HAS happened.

So, what can we do about it? Easy... fit a three core lead, and ground the chassis. Brilliant. Guitarist now safe. Except for the thing now hums like billy-o, because we now have an earth loop. More here.
OK, so what can we do? Remember the isolation transformer we fitted to the Ekco radio? Just the job. This will prevent any earth currents flowing , and prevent the thing humming whilst maintaining electrical safety. 

Here, I've fitted the isolation transformer , and a nice new 3-core mains lead. The Earth is secured to the chassis, using a soldered ring terminal, and a nut, bolt and star washer to ensure good contact
The tape-tensioning mechanism is stripped, cleaned and lubricated.









All cleaned up and ready for the next 30 years of service!