Quantcast
Channel: Arduino Archives - Baltazar Studios
Viewing all articles
Browse latest Browse all 4

Ambient Weather WS-2080 hang fix

$
0
0

A weather station, Ambient Weather WS-2080 that I installed in my backyard has a receiver unit with a pretty nasty hardware issue: occasionally, its USB interface would hang hard. It could happen twice a week or once a month – it is very unpredictable and highly annoying. Once it happens, nothing short of a power reset of the receiver unit would fix it. You’d have to remove the battery or unplug the USB if you powered it through it. I’ve finally got around to fixing it. If you have a similar problem with that weather station, you may be interested to read on…

If this is happening to your unit, you will also know that in addition to the hang, the software that talks to it (“Cumuls” in this case), would also hang trying to read the USB data. This creates an additional problem: you would have to actively monitor the setup daily so you can fix it and not lose any weather data.

Instruments like that should be able to work autonomously for months, years at a time!

Ambient Weather, WS-2080, weather station, powershell, pcb, arduino
WS-2080 Weather Station

I wanted a robust and fully automatic solution since I tried almost anything suggested at various forums, but nothing worked.

My solution to this problem was a set of software scripts to detect when a device hangs and a small Arduino-based dongle board that controls the USB power to the receiver and can hard reset the unit when a problem is detected. As an additional bonus, I also wanted to get an email when the fault (and correction) happens.

Hardware

I used a spare Arduino Nano board and fitted it inside a small phone jack enclosure which I could then mount on the wall between the server PC and a weather station receiver.

The idea was for the server to talk to the Arduino via USB/serial and the Arduino would control a relay which would control the power of the USB connection to the receiver. The USB cable to the receiver would pass through this dongle.

This is a final schematic done in the Eagle software:

USB dongle schematics
USB dongle schematics

and the board layout:

USB dongle layout
USB dongle layout

The board also has a “garage door” terminal. This is hooked up to a switch on my garage door rail and detects when a garage is opened – a part of my home Internet-of-Things network. However, that’s a topic for another blog.

The 5×2 pin connector is a simple USB pass-through and the relay controls its +5V wire. All other USB signals are passed through unmodified.

This is the image of a finished board already fitted in the enclosure:

Board fitted in place
Board fitted in place

Once the board was ready, I mounted it on the wall. I want to thank my friend Brent who created a perfectly fitting (red) enclosure cover on his 3D printer for me!

USB dongle mounted in place
USB dongle mounted in place

It is then connected to my weather station, whose USB power is now fully controlled by the server software through the pass-through dongle.

WS-2080 station in place
WS-2080 station in place

The board contains these parts:

Part     Value                          Device                         Package     Description                
------   ---------------------------    ---------------------------    ---------   --------------------------
C1       68nF                           C-EUC0805                      C0805       CAPACITOR, European symbol 
GARAGE   X                              AK300/2                        AK300/2     CONNECTOR                  
J1                                      0R                             0R/10       Bridge 0R 10mm             
OVERRIDE TL32YO                         TL32YO                         TL3XYO      TINY SWITCH ON - MOM       
R2       4K7                            R-EU_R0805                     R0805       RESISTOR, European symbol  
REED     R560-1D.5-6D                   RR1A                           RR1A        RELAY                      
U$1      ARDUINONANO_V3.0_OPPOSITE_SIDE ARDUINONANO_V3.0_OPPOSITE_SIDE ARDUINONANO Arduino Nano V3.0          
USB      USB                            PINHD-2X5_2.54                 2X05        PIN HEADER

A reed relay with an internal clamping diode from NTE Electronics is used. Its data sheet can be found here.

Software

This is the software that runs on the Arduino Nano board:

/*
 * 2/31/2013 version 1 (garage door switch only)
 * 4/4/2013  version 2 (added control to USB power)
 *
 * Digital pin 2 is connected to a switch to garage door. The return path
 * is to to 5Vcc and that voltage is read when the door remains closed.
 * This minimizes noise and false signals.
 *
 * Every time the switch toggles, serial outputs its new state:
 *
 *  Init
 *  G:0
 *  G:1
 *  G:0
 *  G:1
 * 1 means "Garage door opened"
 * 0 means "Garage door closed"
 *
 * Digital pin 5 is connected to a reed relay controlling the Power wire
 * of an external USB device. The (serial) input is monitored for a incoming
 * codes of '1' (turns the relay on) or '0' (turns the relay off). At the same
 * time the program will output 'I:'+code back to the serial to acknowledge
 * the reception. All other codes except '1' and '0' will be ignored.
 */
#include 

#define PINSW               2       // Garage door switch on D2
#define PINUSB              5       // USB power of D5
#define PINLED              13      // Arduino built-in LED

Bounce bouncer = Bounce(PINSW, 200);

void report(int doorState)
{
    Serial.print("G:");
    Serial.println(doorState);

    // If the door is opened, turn on internal LED
    digitalWrite(PINLED, doorState? HIGH : LOW);
}

void loop()
{
    if (bouncer.update())
    {
        // Pin switch returns "0" when the door remains closed since it
        // completes a circuit from a +5V pullup to the ground.
        // When door opens, switch opens and breaks the loop, leaving
        // only the pull-up on the digital pin, so it returns "1"
        int value = bouncer.read();

        // Value = 1 when the garage door is opened
        report(value);
    }
    
    // Check if a byte is available from the serial port
    if (Serial.available() > 0)
    {
        int b = Serial.read();
        Serial.print("I:");
        Serial.println(b);
        if (b=='1')
            digitalWrite(PINUSB, HIGH);
        if (b=='0')
            digitalWrite(PINUSB, LOW);
    }
}

void setup()
{
    Serial.begin(115200);
    Serial.println("Init");

    pinMode(PINUSB, OUTPUT);
    digitalWrite(PINUSB, HIGH);

    pinMode(PINSW, INPUT);
    digitalWrite(PINSW, HIGH);

    pinMode(PINLED, OUTPUT);

    // Upon initialization, send the starting state
    int value = digitalRead(PINSW);
    report(!value);
}

Since I am using the same setup to detect garage doors being opened and closed, the source contains code to handle that task as well. As with anything else, you may want to just take the main ideas and create your own solutions.

The USB dongle is connected to a Windows Home Server 2011 box, so I made a couple of scripts in Windows PowerShell to monitor for the failure condition which can be identified by Cumulus software not saving its real-time report data file within some time (I selected 60 min). The script was added to the Task Scheduler to run every 1 hour:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File ServerAutomation\Watchdog\CheckTime.ps1

#
# Check the last modification time of a file and compare it to the current time
# If more than X minutes has passed, send email
#
$file = "C:\Cumulus\realtime.txt"

# If the Cumulus process is not running, do not check
$process = Get-Process Cumulus -ErrorAction silentlycontinue
if (!$process)
{
    exit
}

$date = Get-Date
$filedate = (Get-item $file).LastWriteTime
$diffdate = $date.Subtract($filedate)

function sendMail
{
    $EmailFrom = "Automation@devic.home"
    $EmailTo = "gdevic@yahoo.com"
    $Subject = "Notification from Moria"
    $Body = "Cumulus: $file file did not update in 60 min! I will reset USB and restart Cumulus..."
    $SMTPServer = "smtp.gmail.com"
    $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
    $SMTPClient.EnableSsl = $true
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("devic.home", "password");
    $SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
}

$diffdate.TotalMinutes

if ($diffdate.TotalMinutes -ge 60)
{
    # Reset the USB by setting a trigger environment variable (see PostGarageDoorData.ps1)
    cd C:\Cumulus                           # Execute in Cumulus directory
    # Send a signal to reset the USB
    echo Y >> resetusb.txt
    kill -processname Cumulus               # Kill the Cumulus process
    sendMail                                # Send email while the USB is being reset
    sleep 30                                # Wait 30 sec: USB restart can take up to 15
    Start-Process Cumulus.exe               # Restart the Cumulus process
}

The script checks if that file has a timestamp older than 60 minutes, and if it does, it will set a signal (via an environment variable) to another script to reset the power on the USB dongle. At the same time it will also (1) send an email to notify me about the event and (2) reset Cumulus software. PowerShell makes doing all of that really easy.

I used a separate script to reset the USB since I am running some other processes that were combined with it. This is a part of that script that checks for the event and resets the USB:

$line = ""
$previous = "G:0"
[Environment]::SetEnvironmentVariable("RESETUSB", "N", "user")

# Post the initial state to zero out future graphs
C:\python27\python.exe post.py $previous

do
{
    try
    {
        $port = New-Object System.IO.Ports.SerialPort com4,115200,none
        # With a timeout, ReadLine() will cause repeated exceptions when
        # the input buffer is empty. Otherwise, it should wait until a
        # full line (with a \n !) is available
        $port.ReadTimeout = 10000        # 10 seconds
        $port.Open()
        $line = $port.ReadLine()
    }
    catch [TimeoutException]
    {
        Write-Host -NoNewline "."
    }
    finally
    {
        $port.Close()
    }

    # If the $line contains 'G:', send it to the email script
    if ($line.StartsWith("G:"))
    {
        # Post a previous state followed by the new state so they form a square signal
        C:\python27\python.exe post.py $previous
        C:\python27\python.exe post.py $line
        $previous = $line
        $line = ""
    }

    # Check for a request to reboot the USB device
    if (Test-Path("c:\Cumulus\resetusb.txt"))
    {
        del c:\Cumulus\resetusb.txt
        date
        date >> log.txt
        "Resetting the USB!"
        $port = New-Object System.IO.Ports.SerialPort com4,115200,none
        $port.Open()
        $port.Write("0");
        Start-Sleep(5)                    # Wait 5 seconds
        $port.Write("1");
        $port.Close();
    }

} while(1)

It was a satisfying moment when I first got the email from the system: It rebooted the receiver unit, the software and had reset the weather station. It all continued to work as if nothing had happened and you’d not know if you hadn’t checked the weather data and saw a few missing entries. Then I checked the Weather Underground feed and surely enough – a short flat-line of missing data was closely followed by new valid data and all that happened without my intervention.

This is a link to WeatherCloud where I post weather data. This is a RapidFire WU site where the weather conditions are updated every 5 seconds.

Finally, this is a hosted website containing weather data updated by the Cumulus software using one of the many available weather templates.

Backup images

Mask for the board
Mask for the board
Exposure...
Exposure…
Etching...
Etching…
The board is ready
The board is ready
Cut a slot with a nibbler!
Cut a slot with a nibbler!
Testing the Arduino software
Testing the Arduino software
Fitting the board into a convenient enclosure
Fitting the board into a convenient enclosure

The post Ambient Weather WS-2080 hang fix appeared first on Baltazar Studios.


Viewing all articles
Browse latest Browse all 4

Trending Articles