Pages

Saturday 24 May 2014

Practice - Activating a Fan Depending on the Temperature

Description

In this lab we have been experimenting with the comunication between an XBee connected to a PC and another XBee that is taking signals from a sensor to send them (this signals are caught using the DIO ports of the XBee explorer). The information that comes from the sensors is sent from an XBee to the other; the information received by the second XBee will be read serially with a computer using a Python program, that will process the read (e.g. showing it or generating a response). Both XBees work in API mode as in the last practice (Morse Code).

In the first part we will show the messages sent by an XBee which is connected to a LDR, whereas in the second part a motor will be turned on when the temperature reaches a defined value (e.g. 30ºC).

The material we will need is the following:
  • Hookup wires.
  • 1x Arduino board.
  • 1x USB A-to-B cable for the Arduino.
  • 1x XBee radio configured as ZigBee Coordinator API.
  • 1x XBee radio configured as ZigBee Router API.
  • 2x USB cable for the XBee.
  • 2x XBee Explorer.
  • 1x Breakout board.
  • 1x Motor.
  • 1x Temperature Sensor (LM35).
  • 1x Transistor.
  • 1x LDR (Light Dependent Resistor).
Moreover, again we leave here some of the software you will need (the same as in the previous practice). 
The installation is explained in the previous practice too, review it if you have not seen it yet.

Part 1 - Warm Up

As a warm up we did the activity explained in the course guide [1]. It consists in a circuit formed by an LDR, whose analogic values are sent to an XBee through one of its pins; this information is received at another XBee which is plugged to a computer. This computer executes a Python program which reads the messages when received and shows them through the screen. Note that any Arduino is being used here.

Figure 1: Setup of  the XBee that sends LDR state to the computer connected XBee

In the following screenshots you can see the messages that are sent. You can see that two of them in a red rectangle: the first one represents a measure with the room plenty of light, and the second one without light.

Figure 2: Receiving values from XBee

This task can be done in two different ways: sinchronously and asinchronously. The code is attached below.

Synchronous code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import serial
from xbee import ZigBee

print 'Printing data from remote XBee'

serial_port = serial.Serial('COM4', 9600)
zigbee = ZigBee(serial_port, escape=True)

while True:
    try:
        print zigbee.wait_read_frame()
    except KeyboardInterrupt:
        break

zigbee.halt()
serial_port.close()

Asynchronous code


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import serial
import time
from xbee import ZigBee

print 'Asynchronously printing data from remote XBee'

serial_port = serial.Serial('/dev/ttyUSB0', 9600)

def print_data(data):
    """
    This method is called whenever data is received.
    Its only argument is the data within the frame.
    """
    print data['samples']

zigbee = ZigBee(serial_port, escaped=True, callback = print_data)

while True:
    try:
        time.sleep(0.001)
    except KeyboardInterrupt:
        break

zigbee.halt()
serial_port.close()

Part 2 - Activating a Fan

On this extra project part, we are going to design a system that will allow us to refrigerate a server's room (e.g. a CDN). The heat production produced by the servers on data center is one of the main problems that administrators have to face. The heat excess in servers room negatively impacts the equipment performance and shortens their useful life. Also, if we are dealing with critical systems like nuclear centers, having a real-time control on the temperature is a priority. So, let us try to develop a system that automatically refrigerates the servers when needed, making the administrators could invest their time in other useful tasks.

On the room's side we need:

  • 1x Temperature Sensor.
  • 1x Fan (motor).
  • 1x Xbee.
  • 1x Arduino Uno.
  • A way to feed the Arduino (a normal PC will be enough).

On the control center we will need:

  • 1x Xbee
  • 1x PC running python code

Figure 3: System overview
As shown above, the two main parts of the whole system communicate each other by using a pair of Xbee modules. On the server side, the Xbee will send the data captured by the temperature sensor. The Xbee situated on the control center side will get this data and forward it to the PC, which runs a python code that is able to decode the received data and compare it with a predefined temperature threshold. When the threshold is overcome, the code will generate an alert packet advising the Arduino on the servers side to activate the ventilator (motor). This packet, naturally, will be forwarded from the control center Xbee to the server side Xbee.

It is important to note that, because of collisions high probability, the Xbee on the servers side will transmit the temperature data periodically. That is, sending a temperature data packet, waiting for possible motor activation packet, and then, if no packet is received, sending the next captured temperature.

Respect to the code, we have to take into account that the LM35 temperature sensor does not provide the temperature directly. We have found in [2] that a formula has to be computed in order to get the temperature depending on the voltage; since our voltage is 3.3 V, the formula we get is: 3.3 * 100 * readValue / 1024. However, in the code there is this option and another one that we have manually computed by knowing the real temperature of the room in which we were doing the lab: readValue * 18.0 / 212.0.

Phographs

Figure 4: Photograph of the whole system

Figure 5: Photograph of the sensor (temperature) and actuator (motor) system

Final setup image


Figure 6: Final setup of the temperature based fan

Video


Arduino Code


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// named constants for the switch and motor pins
const int STATE_PIN = 2; // the number of the State pin
const int  FAN_PIN =  5; // the number of the motor pin

int DETstate = 0;  // variable for reading the state detector status

void setup() {
  // initialize the motor pin as an output:
  pinMode(FAN_PIN, OUTPUT);
  digitalWrite(FAN_PIN, LOW); 
  // initialize the switch pin as an input:
  pinMode(DETstate, INPUT);
  Serial.begin(9600); 
}

void loop(){
  // read the state of the Threshold value:
  DETstate = digitalRead(STATE_PIN);
  // check if the activationg motor order is rx
  if (DETstate == HIGH) {     
    // turn fan on:    
    digitalWrite(FAN_PIN, HIGH);  
  } 
  else {
    // turn fan off:
    digitalWrite(FAN_PIN, LOW); 
  }
  delay(10);
}

Python Code (XBee connected to computer)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import serial
from xbee import ZigBee

def getTemperatureFromData(data):
 temperature = data['samples'][0]['adc-0']
 # temperature = temperature*18.0/212.0
 temperature = 3.3 * temperature * 100.0 / 1024.0
 return temperature

def turnFanOn(xbee):
    print 'Threshold exceeded! Activating Fans'
    xbee.send('remote_at',
                  frame_id='A',
                  dest_addr_long='\x00\x13\xA2\x00\x40\x8B\x96\x2E',
                  dest_addr='\xFF\xFE',
                  options='\x02',
                  command='D1',
                  parameter='\x05')

def turnFanOff(xbee):
    xbee.send('remote_at',
                  frame_id='A',
                  dest_addr_long='\x00\x13\xA2\x00\x40\x8B\x96\x2E',
                  dest_addr='\xFF\xFE',
                  options='\x02',
                  command='D1',
                  parameter='\x04')   
   
def main():
    print 'Receiving temperature values...'
    serialPort = serial.Serial('COM4', 9600)
    xbee = ZigBee(serialPort, escaped=True)
 
    while True:
  try:
   data = xbee.wait_read_frame()
   if data.keys().count('samples') != 0:
    temperature = getTemperatureFromData(data)
    print temperature
    if (temperature > 21.0):
     turnFanOn(xbee)
    else:
     turnFanOff(xbee)
   
  except KeyboardInterrupt:
   xbee.send('remote_at',
       frame_id='A',
       dest_addr_long='\x00\x13\xA2\x00\x40\x8B\x96\x2E',
       dest_addr='\xFF\xFE',
       options='\x02',
       command='D1',
       parameter='\x04')
   break
 
 xbee.halt()
 serialPort.close()
 
if __name__ == '__main__':
 main()
else:
 pass 
  

References

[3] Pictures:

Wednesday 14 May 2014

Practice - Morse Code Player

Description

This time we are going to perform a system that executes specific tasks according to the communication between two XBee. As usual, we are dividing this practicaL exercise into two parts. The first one will show you how to configurate the XBee modules and the Arduino in order to blink a LED at the receiver part. The second part extends that functionality, so we are going to create a Morse code player, which reproduces the characters introduced on the sender side into Morse. To coordinate all this stuff we are going to use Python code with XBee libraries on the sender side.

So, the material that we are going to need is exposed below:
  • Hookup wires.
  • 1 x Arduino board.
  • 1 x USB A-to-B cable for the Arduino.
  • 1 x XBee radio configured as ZigBee Coordinator API.
  • 1 x XBee radio configured as ZigBee Router API.
  • 1 x Breakout board.
  • 1 x USB cable for the XBee.
  • 1 x LED.
  • 1 x Buzzer for output.
The software that you will need to support all this is:
Remember you can find the code used in the code section.

Part 1

The first thing we must do is to install and configure python and the needed libraries for our purpose. After downloading the Python we should see a wizard like the shown on the image below:

Figure 1: Python Wizard

You only have to follow the steps and install it. If you want to execute Python programs with "cmd" tool you should add the directory of the Python to the "path" variable (System > Advanced system settings > Environment variables > System variables > Path ). After doing that you should see the Python version at cmd by typing "python":

Figure 2: Python installation and configuration check

To complete the configuration of the system we must install the XBee and PySerial libraries by the following way:
  • Download the XBee library from the given link (if you have problems with it you can go to the 2nd link and pick the version that suits better to you computer).
Figure 3: XBee library download
  •  Install it by typing "python setup.py install" on the directory where you stored it (C:\Users\User\Destop\XBee-2.1.0 in our case):
Figure 4: XBee library install
  • Download the "pyserial" library and to exactly the same to install it.
Now we have the software properly installed, but the last thing we must do before building the circuit and implementing the code is to set the XBee modules on the API mode. For the coordinator we set it as "ZigBee Coordinator API":

Figure 5: XBee mode
We do the same for the router ("ZigBee Router API"). We also have to enable the API mode at both XBee by setting the "AP" field with number 2.

Figure 6: Enable API mode

The  circuit that we have to build by now is quite simple: a LED connected to the  D1 port of the XBee (note that in this case we only use the arduino to feed the XBee):

Figure 7: Circuit part 1
The code that we must implement on the sender side will send packets to the receiver XBee (we can also send broadcast packets on the same PAN ID with dest_addr_long='\x00\x00\x00\x00\x00\x00\xFF\xFF') that will enable and disable the D1 port in order to let the current path and activate the LED. We also have to take into account in which port we have placed the XBee (COM5 in our case).

To execute it we go to the directory where it is placed and we type "python nameOfTheFile.py"

Figure 8: Code execution

Code Part 1 [3]


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#! /usr/bin/python

from xbee import ZigBee
import serial
import time

ser = serial.Serial('COM5', 9600)
xbee = ZigBee(ser, escaped=True)

while True:
    try:
        xbee.send('remote_at',
                  frame_id='A',
                  dest_addr_long='\x00\x13\xA2\x00\x40\x8B\x45\xC8',
                  dest_addr='\xFF\xFE',
                  options='\x02',
                  command='D1',
                  parameter='\x05')
        print("Open port, LED ON on other side")  
        time.sleep(5)
        
        xbee.send('remote_at',
                  frame_id='A',
                  dest_addr_long='\x00\x13\xA2\x00\x40\x8B\x45\xC8',
                  dest_addr='\xFF\xFE',
                  options='\x02',
                  command='D1',
                  parameter='\x04')
        print("Closed port, LED OFF on the other side")
          
        time.sleep(5)
 
  
    except KeyboardInterrupt:
        break

xbee.send('remote_at',
          frame_id='A',
          dest_addr_long='\x00\x00\x00\x00\x00\x00\xFF\xFF',
          dest_addr='\xFF\xFE',
          options='\x02',
          command='D1',
          parameter='\x04')

ser.close()

Images Part 1

Figure 9: Image Circuit Part 1

Part 2

In this second part we are going to change a bit the implementation of the sender side and we are going to add functionalities that the Arduino must implement in order to play the received characters in morse code. The figure below shows the International Morse Code, which we used at the Arduino code for the player:

Figure 10: International Morse Code [4]




We have the same scenario as in part 1, but we have added a LED and a buzzer, which are connected to the Arduino in order to process the information received from the XBee (which receives the characters from the sender XBee).

Figure 11: Circuit part 2
The next step is to implement the "Sender" and the "MorsePlayer" codes and we will see how the LED is turned ON and the buzzers sounds when we receive a character, playing it in morse code. The caracthers are introduced through the keyboard using the Python console.

Images

Figure 12: Circuit part 2 (1)
Figure 13: Cicuit part 2 (2)
Figure 14: Circuit part 2 (3)

Video



Code Part 2: Sender [5]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#! /usr/bin/python

from xbee import ZigBee
from array import *
import serial
import time
from datetime import datetime

ser = serial.Serial('COM4', 9600)
xbee = ZigBee(ser, escaped=True)

while True:
 try:
  input = raw_input('Enter your letter:')
  for c in input:
   tstart = datetime.now()
   xbee.send('tx',
   frame_id='A',
   dest_addr_long='\x00\x13\xA2\x00\x40\x8B\x45\xC8',
   dest_addr='\xFF\xFE',
   data=c)
   response = xbee.wait_read_frame()
   tend = datetime.now()
   print c
   print tend-tstart
   time.sleep(2)
 except KeyboardInterrupt:
  break
  
ser.close()


Code Part 2: Morse Player


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <XBee.h>

// Pins
const int ledPin = 13;
const int buzzerPin = 5;

/**
 * Morse Codes
 *  "s" for short (.), "l" for long (-) 
 */
const char longNote = 'l';
const char shortNote = 's';
 
// Morse code for Alphabet
const String letter[26] = {
  "sl","lsss","lsls","lss","s","ssls","lls","ssss","ss","slll","lsl",
  "slss","ll","ls","lll","slls","llsl","sls","sss","l","ssl","sssl","sll","lssl","lsll","llss"}; 

// Morse code for Numbers
const String number[10]= {
  "lllll","sllll","sslll","sssll","ssssl","sssss","lssss","llsss","lllss","lllls"};

/**
 * XBee objects
 */
XBee xbee;
XBeeResponse response;
// create reusable response objects for responses we expect to handle
ZBRxResponse rx;

void setup()
{
  Serial.begin(9600);

  pinMode(ledPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);

  xbee = XBee();
  response = XBeeResponse();
  rx = ZBRxResponse();

  flashLed(ledPin, 10, 50);
}

void loop()
{
  // 1. This will read any data that is available:
  xbee.readPacket();
  if (xbee.getResponse().isAvailable())
  {
    if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE)
    {
      xbee.getResponse().getZBRxResponse(rx);
      Serial.println(rx.getData(0));
      playCode(rx.getData(0));
    }
  }
}

// Flash the LED for certain number of times and delay between flashes
void flashLed(int pin, int times, int wait)
{
  for (int i = 0; i < times; ++i)
  {
    digitalWrite(pin, HIGH);
    delay(wait);
    digitalWrite(pin, LOW);

    if (i + 1 < times)
    {
      delay(wait);
    }
  }
}

// Play the required tone for the char or int transmitted
void playCode(int ASCII_value)
{
  int intValue = ASCII_value - '0';

  // Integer read
  if (intValue >= 0 && intValue <= 9)
  {
    String toPlay = number[intValue];
    Serial.println(toPlay);
    for (int i = 0; i < toPlay.length(); ++i)
    {
      Serial.println(toPlay[i]);
      if(toPlay.charAt(i) == longNote)    
        largeTone();
      else if(toPlay.charAt(i) == shortNote)
        shortTone();
    } 
  }
  else // Char (A-Z) read
  {
    String toPlay = letter[ASCII_value-65];
    Serial.println(toPlay);
    for (int i = 0; i < toPlay.length(); ++i)
    {
      Serial.println(toPlay[i]);
      if (toPlay.charAt(i) == longNote)    
        largeTone();
      else if (toPlay.charAt(i) == shortNote)
        shortTone();
    }    
  }
}

void largeTone()
{
  delay(50);
  digitalWrite(ledPin, HIGH);
  analogWrite(buzzerPin, 2000);
  delay(500);
  digitalWrite(ledPin, LOW);
  analogWrite(buzzerPin, 0);
}

void shortTone()
{
  delay(50);
  digitalWrite(ledPin, HIGH);
  analogWrite(buzzerPin, 2000);
  delay(100);
  digitalWrite(ledPin, LOW);
  analogWrite(buzzerPin, 0);
}


References

[1] Python software and libraries, retrieved from: https://www.python.org/
[2] XBee library for Arduino, retrieved from: https://code.google.com/p/xbee-arduino/
[3] Code for activate/desactivate D1 port on the receiver side by Jaume Barceló and Luis Sanabria 
[4] International Morse Code, retrieved from: http://en.wikipedia.org/wiki/Morse_code
[5] Version of the code "modified3-blink-LED", by Jaume Barceló and Luis Sanabria

Friday 9 May 2014

Practice - Light Based Alarm (Sunset Project)

Description

This time we are going to show you how we can interact with ambient light through sensors. As usually, we will propose you two main parts for this lab exercise: the first one shows how we implemented the WSN MOOC proposal, while the second part goes beyond that, so we will also show you how to activate a LED and a buzzer on the sensor side in order to prevent thefts. The stuff we are using this time is showed below [1]:
  • Breadboard (two better than one).
  • Jumper wire Arduino UNO (and USB-A-to-B cable).
  • 2 XBee.
  • 2 XBee explorer (and at least one USB-to-mini-USB cable).
  • Four LEDs (white, red, blue, green).
  • A buzzer.
  • A photoresistor (or Light Dependant Resistance).
  • 10Kohm in the dark, 1Kohm in bright light 20Kohm resistor .
Remember you can download the code in the code section.

Part 1

The idea is to implement a voltage divider with a fixed resistance and a variable one in order to take the value between them. This will allow us to detect the voltage variations, which will let knowing the state of the ambient light. When the photoresistor detects bright light, its resistance value decreases, so the output voltage decreases. The opposite behavior happens when it detects a dark environment. The following schema shows you the logical circuit that we are implementing:

Figure 1: Voltage divider
The value that we are going to find at the point of interest is:


Once we know how the photoresistor works and how we must take benefit of it, we can build the circuit that will turn on a LED depending on the ambient light received on the sensor’s side. The following picture shows the connections that have to be done for this part:

Figure 2: Sunset connections [2]
Before implementing the code we have to configure the Xbee modules by following these steps:

1. The processing part must implement coordinator tasks, so we set a PAN ID (BFB7 in our case):

Figure 3: Coordinator node

2. The sensor side is the router part, so we set the same PAN ID as for the coordinator and we enable the “JV Channel Verification” field:

Figure 4: Router Node 1

3. We also configure the I/O settings that allow us to convert the received values from the circuit into digital characters for transmission: ADC (Analog-Digital Conversion) option.

Figure 5: Router Node 2

4. The last step consists in changing the IO Sampling Rate into 255 ms (0xFF) in order to avoid some communication troubles:

Figure 6: Router Node 3

Circuit Photography

  

Processing Side Code (Part 1)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
int LED_NIGHT = 10;
int LED_SUNSET = 11;
int LED_DAY = 12;
int debugLED = 13;
int analogValue = 0;
// Upper boundaries
int DAYup = 750;
int SUNSETup = 950;

void setup() {
  pinMode(LED_DAY,OUTPUT);
  pinMode(LED_SUNSET,OUTPUT);
  pinMode(LED_NIGHT,OUTPUT);
  pinMode(debugLED,OUTPUT);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(LED_NIGHT, LOW);
  digitalWrite(LED_SUNSET, LOW);
  digitalWrite(LED_DAY, LOW);
  // make sure everything we need is in the buffer
  if (Serial.available() >= 21) {
    // look for the start byte
    if (Serial.read() == 0x7E) {
      //blink debug LED to indicate when data is received
      digitalWrite(debugLED, HIGH);
      delay(10);
      digitalWrite(debugLED, LOW);
      // read the variables that we're not using out of the buffer
      for (int i = 0; i<18; i++) {
        byte discard = Serial.read();
      }
      int analogHigh = Serial.read();
      int analogLow = Serial.read();
      analogValue = analogLow + (analogHigh * 256);
      Serial.print("Analog value ");
      Serial.println(analogValue);
    }
  }

  // DAY TIME
  if (analogValue > 0 && analogValue <= DAYup) {
    digitalWrite(LED_DAY, HIGH);
    delay(10);
    digitalWrite(LED_DAY, LOW);
  }

  // SUNSET TIME
  if (analogValue > DAYup && analogValue <= SUNSETup) {
    digitalWrite(LED_SUNSET, HIGH);
    delay(10);
    digitalWrite(LED_SUNSET, LOW);
  }

  // NIGHT TIME
  if (analogValue > SUNSETup && analogValue <= 1023) {
    digitalWrite(LED_NIGHT, HIGH);
    delay(10);
    digitalWrite(LED_NIGHT, LOW);
  }
}

Part 2

To extend the practical exercise seen on this entry we have deployed a buzzer that makes sounds when the state of the sensor changes. It could be useful for detecting movement (detecting a shadow) and then displaying the alarm to frighten thieves.

So, the behavior of our circuit is going to be the same as shown before, but we are adding communication between the coordinator and the router, in order to transmit a command to activate the port D1 at the sensor side, that will make the buzzer sound.

For this purpose, we have to use the "setRemoteState" function, which sends information through the serial channel with the value (as input of the function) that enables or disables the specific port with we are dealing to.

In our case, we have implemented that the Programmer side checks every 10 seconds if the status of the photoreceptor has changed from day to night. If yes, we call the "setRemoteState" function to send "05". Otherwise, we send "04".

More information about XBee 802.15.4 digital input/output passing can be found on the following link: http://www.digi.com/support/kbase/kbaseresultdetl?id=2188

Circuit Assembly



Circuit Photographies   





Processing Side Code (Part 2)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
int LED_NIGHT = 10;
int LED_SUNSET = 11;
int LED_DAY = 12;
int debugLED = 13;
int analogValue = 0;
// Upper boundaries
int DAYup = 750;
int SUNSETup = 950;

int remoteIndicator = false; // keeps track of the desired remote on/off state
int lastRemoteIndicator = false; // record of prior remote state

unsigned long lastSent = 0; // records last time the remote was re-set to keep it in sync

void setup() {
  pinMode(LED_DAY,OUTPUT);
  pinMode(LED_SUNSET,OUTPUT);
  pinMode(LED_NIGHT,OUTPUT);
  pinMode(debugLED,OUTPUT);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(LED_NIGHT, LOW);
  digitalWrite(LED_SUNSET, LOW);
  digitalWrite(LED_DAY, LOW);
  // make sure everything we need is in the buffer
  if (Serial.available() >= 23) {
    // look for the start byte
    if (Serial.read() == 0x7E) {
      //blink debug LED to indicate when data is received
      digitalWrite(debugLED, HIGH);
      delay(10);
      digitalWrite(debugLED, LOW);
      // read the variables that we're not using out of the buffer
      for (int i = 0; i<20; i++) {
        byte discard = Serial.read();
      }
      int analogHigh = Serial.read();
      int analogLow = Serial.read();
      analogValue = analogLow + (analogHigh * 256);
      Serial.print("Analog value ");
      Serial.println(analogValue);
    }
  }

  // DAY TIME
  if (analogValue > 0 && analogValue <= DAYup) {
    digitalWrite(LED_DAY, HIGH);
    delay(10);
    digitalWrite(LED_DAY, LOW);
    remoteIndicator = false;
  }

  // SUNSET TIME
  if (analogValue > DAYup && analogValue <= SUNSETup) {
    digitalWrite(LED_SUNSET, HIGH);
    delay(10);
    digitalWrite(LED_SUNSET, LOW);
    remoteIndicator = false;
  }

  // NIGHT TIME
  if (analogValue > SUNSETup && analogValue <= 1023) {
    digitalWrite(LED_NIGHT, HIGH);
    delay(10);
    digitalWrite(LED_NIGHT, LOW);
    remoteIndicator = true;
  }

  // set the indicator immediately when there's a state change
  if (remoteIndicator != lastRemoteIndicator) {
    if (remoteIndicator==false) setRemoteState(0x4);
    if (remoteIndicator==true) setRemoteState(0x5);
    lastRemoteIndicator = remoteIndicator;
  }
  // re-set the indicator occasionally in case it's out of sync
  if (millis() - lastSent > 10000 ) {
    if (remoteIndicator==false) setRemoteState(0x4);
    if (remoteIndicator==true) setRemoteState(0x5);
    lastSent = millis();
  }

}


void setRemoteState(int value) {
  Serial.write(0x7e);//Start byte
  Serial.write((byte)0x0);//Length
  Serial.write(0x10);//Length High
  Serial.write(0x17);//AT Command Request
  Serial.write((byte)0x0);//Frame ID
  Serial.write((byte)0x0);//Serial Number of Destination
  Serial.write((byte)0x0);
  Serial.write((byte)0x0);
  Serial.write((byte)0x0);
  Serial.write((byte)0x0);
  Serial.write((byte)0x0);
  Serial.write(0xFF);
  Serial.write(0xFF);//End of Serial Number of Destinition

  // 16 bit of recipient or 0xFFFE if unknown
  Serial.write(0xFF);
  Serial.write(0xFE);
  Serial.write(0x02);//Apply changes immediately

  //Command name in ASCII characters
  Serial.write('D');
  Serial.write('1');

  //command data in as many bytes after length bytes
  Serial.write(value);

  //checksum is all bytes after length bytes
  long sum = 0x17 + 0xFF+ 0xFF + 0xFF + 0xFE + 0x02 + 'D' + '1' + value;
  Serial.write (0xFF - ( sum & 0xFF) );
  delay(10); // avoiding overwhelming
} 


Buzzer Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Pin where the buzzer is connected
const int BELL = 5;
const int PIN_STATE = 2;
// Light detector state
int DETstate = 0;
// Tone variables
float sinVal;
int toneVal;
void setup()
{
  pinMode(BELL, OUTPUT);
  Serial.begin(9600); 
}

void loop()
{
  DETstate = digitalRead(PIN_STATE);
  if (DETstate == HIGH){
    for (int x=0; x<180; x++) {
      // convert degrees to radians then obtain sin value
      sinVal = (sin(x*(3.1412/180)));
      // generate a frequency from the sin value
      toneVal = 2000+(int(sinVal*1000));
      tone(BELL, toneVal);
       
    }
    delay(10);
    noTone(BELL);
    //analogWrite(BELL, 0); 
  }


}


Video


References

[1] Material list retrieved from “WSN course guide”, chapter 11 (Sunset Sensor), made by Jaume Barceló and Luis Sanabria 

[2] Image retrieved from “WSN course guide”, chapter 11 (Sunset Sensor), made by Jaume Barceló and Luis Sanabria