Hello Everyone,
This post covers the last of the sensors and the cameras. Included in this post are the Carbon Monoxide and Natural Gas sensors, the Range solenoid value, and both cameras. I decided to document the last of the hardware and software in this post and create a separate post for the summary.
The original camera kits I tried did not work out (Defender Security 720p DIY Surveillance Camera Module with WiFi. There was a quick start guide in the box. I never could connect to the web site documented in the quick start guide. So, there is no hardware/software support for the kit. The kit came with the camera, a motion sensor, microphone, and a micro SD board. Everything plugged into a circuit board that contained WiFi and software to access the camera, motion sensor, microphone, and the SD card. There was no way to access the software on the board. You have to download mobile software to access the devices on the board. I was able to access and connect one of the cameras, but not the other. I could not figure out how to get the motion sensor to work. It did not have a slot to connect a speaker. Therefore, I could not use it for two-way communications without adding additional hardware.
I decided to try a different camera, a Siepem WiFi Security Camera. This camera also came with a quick start guide. It also has a support website with additional documentation.
The camera has WiFi, a micro SD card slot, cloud access, a microphone, a speaker, tilt, pan, night time mode, motion detection, and sound detection. I was able to connect to the cameras and view them on my Android phone, via the Android app. I did not plan to cover the installation of the cameras in the post, since all I did was follow the quick start guide. However, I will review the camers in my next post.
The details for adding the CO (MQ-7) sensor, the Gas (MQ-4) sensor, the Electric Solenoid, and camera design are given in the sections below:
Section I – CO (MQ-7) and Gas (MQ-4) Sensor Design
Section II – Electric Solenoid Design
Section III – Camera Design
Section IV – Code common to all Hardware
Section V – Code for CO Sensor
Section VI – Code for Gas Sensor
Section VII – Code for Electric Solenoid
Section VIII – Linux Tips
Working on the summary now.
Talk to you soon.
Quote of the Moment -
Anyone who has never made a mistake has never tried anything new.
-- Albert Einstein
Previous Bluetooth Challenge Home Security System Posts |
Bluetooth Challenge - Home Security System - Blog Post VIII |
Bluetooth Challenge - Home Security System - Blog Post IX |
Section I – CO (MQ-7) and Gas (MQ-4) Sensor Design
The software design is simple, similar to the PIR sensor design (Figure 1). The differences are minor, such as the alert message and the GPIO pins used. However, the hardware design is more complicated for the gas sensors. This especially true for the MQ-7 CO sensor.
The MQ-7 CO sensor requires that the sensor is heated for 60 seconds (requires 5 volts), then take measurements during the 90 second unheated phase (requires 1.4 volts). The pins on the Arduino only provide 40mA, however the sensor pulls 150 mA from the circuit. I could have used a separate power supply for the sensor. Instead, I added an NPN transistor as a current amplifier (Figures 2 & 3).
The transistor is connected to one of the PWM pins on the Arduino (Pin 10). I use a pulse width modulation of 255 to provide 5 volts during the heating phase and change the value to 87 to bring the voltage down to 1.4 volts during the measurement phase. I added capacitors to smooth out the current to help prevent distortion in the readings.
The 10K resistor (R1) is used to create a voltage divider. Voltage on sensor's output is equal to R1 / (R1 + Rs) * 5V, where Rs is current sensor's resistance. Sensor resistance depends on the CO concentration, therefore the voltage changes accordingly.
The sensor requires calibration to get accurate readings. To get the most accurate readings a known level of CO is required. I have seen several alternate methods suggested. One, is put a glass jar over a lit candle. When the candle goes out, slip the sensor in the container and take readings. You can search the Internet for other methods.
Note: Keep in mind this is a prototype, not meant for production use. If you plan on using this sensor where lives are at stake make sure you calibrate the sensor properly. Also, you may want to consider a more expense sensor.
The gas sensor does not require the use of the heating / non-heating cycles. It can run constantly at 5 volts. However, it still pulls too many amps to attach a GPIO pin directly to it. Therefore, I kept the same hardware design as with the CO sensor. I just keep the PWM value at 255. Also, like the MQ-7 the MQ-4 must be calibrated to get accurate readings.
Figure 1.
Figure 2.
Figure 3.
Section II – Electric Solenoid Design
The design of the Electric Solenoid is similar to the design for the light switch (Figure 4). Its designed to allow the home owner to turn a gas value open or closed. The electric solenoid is connected to the Arduino via a relay switch (Figure 5). Whenever the home owner presses the Natural Gas Sensor button on the web page it will send a signal to the Arduino requesting it to either open or close the gas value. The Arduino will either set GPIO pin 8 (connected to the relay switch) high or low depending on whether the request was to open or close the gas value.
Section III – Camera Design
The camera design is simple (Figure 6) since the camera I am using is Internet enabled and comes with its own Android and IOS apps.
The features for the camera include (Figure 7):
- SD card and Cloud storage
- Allows video recording and pictures
- Two-way voice communications
- Tilt and Panning
- Ability to add multiple cameras to the app.
- Motion and sound detection
- Night vision
There was no programming involved. Just download the app and follow the instructions.
Figure 6.
Figure 7.
Section IV – Code common to all Hardware
There are several files that contain code for all the devices covered in this blog. I will cover the changes to those files in this section instead of covering them in three different sections. The files that are specific to a particular device with be covered in separate sections.
hss-controller.py
The changes made to the hss-controller file are given below (Figure 8):
Lines 11-13 contain the import statements for the new devices.
The Bluetooth addresses were added on Lines 19-21.
Lines 38-41 create and connect to the socket for the CO sensor. The thread for the CO sensor is also started.
Lines 42-45 create and connect to the socket for the Gas sensor. The thread for the Gas sensor is also started.
Lines 46-49 create and connect to the socket for the Range sensor. The thread for the Range sensor is also started.
import Adafruit_BBIO.GPIO as GPIO import serial import bluetooth import time from threading import Thread import alert import bluetoothSockets import pirSensorThread import lightThread import garageThread import coSensorThread import gasSensorThread import rangeThread pirSensorStatus = "0"; bluetoothAddress = ["00:14:03:06:68:26", # PIR Sensor "00:14:03:06:68:93", # Light 1 "00:14:03:06:67:21", # Light 2 "00:14:03:06:65:0B", # Garage Door "00:14:03:06:68:3D", # CO Sensor "00:14:03:05:08:37", # GAS Sensor "00:14:03:06:68:9A"] # Gas Range pirSocket = bluetoothSockets.CreateSocket() bluetoothSockets.ConnectSocket(pirSocket, bluetoothAddress[0], 1) t1 = Thread(target=pirSensorThread.pir, args=(pirSocket,)) t1.start() light1Socket = bluetoothSockets.CreateSocket() bluetoothSockets.ConnectSocket(light1Socket, bluetoothAddress[1], 1) t2 = Thread(target=lightThread.light1, args=(light1Socket,)) t2.start() light2Socket = bluetoothSockets.CreateSocket() bluetoothSockets.ConnectSocket(light2Socket, bluetoothAddress[2], 1) t3 = Thread(target=lightThread.light2, args=(light2Socket,)) t3.start() garageSocket = bluetoothSockets.CreateSocket() bluetoothSockets.ConnectSocket(garageSocket, bluetoothAddress[3], 1) t4 = Thread(target=garageThread.garageDoor, args=(garageSocket,)) t4.start() coSocket = bluetoothSockets.CreateSocket() bluetoothSockets.ConnectSocket(coSocket, bluetoothAddress[4], 1) t5 = Thread(target=coSensorThread.coSendor, args=(coSocket,)) t5.start() gasSocket = bluetoothSockets.CreateSocket() bluetoothSockets.ConnectSocket(gasSocket, bluetoothAddress[5], 1) t6 = Thread(target=gasSensorThread.gasSendor, args=(coSocket,)) t6.start() rangeSocket = bluetoothSockets.CreateSocket() bluetoothSockets.ConnectSocket(rangeSocket, bluetoothAddress[6], 1) t7 = Thread(target=rangeThread.gasRange, args=(coSocket,)) t7.start() while (1 == 1): time.sleep(10)
Figure 8.
bluetoothSockets.py
import bluetooth import time import common import parseData def CreateSocket(): sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM ) return sock def ConnectSocket(sock, serverAddr, port): sock.connect((serverAddr, port)) sendcount=sock.send("Hello Bluetooth Device!!!") def ReceiveData(socket): receiveBuffer = "" bluetoothData = "" print("ReceiveData") dataNotReceived = True while (dataNotReceived): receiveBuffer = socket.recv(80) bluetoothData = bluetoothData + receiveBuffer if (receiveBuffer.endswith("$")): dataNotReceived = False if (dataNotReceived): x = 1 else: parseData.parseBluetoothData(bluetoothData) populateBluetoothRecord(bluetoothData) def populateBluetoothRecord(bluetoothData): if (common.destination_Adapter_Id == "000" and common.source_Adapter_Id == "001"): parseData.parsePirSensorData(bluetoothData) common.pirSensorData = bluetoothData if (common.destination_Adapter_Id == "000" and common.source_Adapter_Id == "004"): parseData.parseGarageDoorData(bluetoothData) common.garageDoorData = bluetoothData if (common.destination_Adapter_Id == "000" and common.source_Adapter_Id == "005"): parseData.parseCoSensorData(bluetoothData) common.coSensorData = bluetoothData if (common.destination_Adapter_Id == "000" and common.source_Adapter_Id == "006"): parseData.parseGasSensorData(bluetoothData) common.gasSensorData = bluetoothData
Figure 9.
The changes for the common file are given below (Figure 10):
Lines 13-16 contain the variables used to hold the data passed from the CO sensor module.
Lines 17-20 contain the variables used to hold the data passed from the Gas sensor module.
The variable on Line 25 is used to hold the data used to parse the data into Lines 13-16.
The variable on Line 26 is used to hold the data used to parse the data into Lines 17-20.
Line 29 contains the variable used to keep track of the status of the CO sensor, triggered (1) or not triggered (0).
Line 30 contains the variable used to keep track of the status of the Gas sensor, triggered (1) or not triggered (0).
source_Adapter_Id = "" destination_Adapter_Id = "" max_Transmission_Count = "" status = "" GDD_source_Adapter_Id = "" GDD_destination_Adapter_Id = "" GDD_max_Transmission_Count = "" GDD_status = "" PSD_source_Adapter_Id = "" PSD_destination_Adapter_Id = "" PSD_max_Transmission_Count = "" PSD_status = "" CO_source_Adapter_Id = "" CO_destination_Adapter_Id = "" CO_max_Transmission_Count = "" CO_status = "" GAS_source_Adapter_Id = "" GAS_destination_Adapter_Id = "" GAS_max_Transmission_Count = "" GAS_status = "" pirSensorData = "" lightSwitch1Data = "" lightSwitch2Data = "" garageDoorData = "" coSensorData = "" gasSensorData = "" garageDoorStatus = "closed" pirSensorStatus = 0 coSensorStatus = "0" gasSensorStatus = "0"
Figure 10.
import common def parseBluetoothData(bluetoothData): common.source_Adapter_Id = bluetoothData[0:3] common.destination_Adapter_Id = bluetoothData[3:6] common.max_Transmission_Count = bluetoothData[6:8] common.status = bluetoothData[8:9] def parseGarageDoorData(bluetoothData): common.GDD_source_Adapter_Id = bluetoothData[0:3] common.GDD_destination_Adapter_Id = bluetoothData[3:6] common.GDD_max_Transmission_Count = bluetoothData[6:8] common.GDD_status = bluetoothData[8:9] def parseCoSensorData(bluetoothData): common.CO_source_Adapter_Id = bluetoothData[0:3] common.CO_destination_Adapter_Id = bluetoothData[3:6] common.CO_max_Transmission_Count = bluetoothData[6:8] common.CO_status = bluetoothData[8:9] def parseGasSensorData(bluetoothData): common.GAS_source_Adapter_Id = bluetoothData[0:3] common.GAS_destination_Adapter_Id = bluetoothData[3:6] common.GAS_max_Transmission_Count = bluetoothData[6:8] common.GAS_status = bluetoothData[8:9] def parsePirSensorData(bluetoothData): common.PSD_source_Adapter_Id = bluetoothData[0:3] common.PSD_destination_Adapter_Id = bluetoothData[3:6] common.PSD_max_Transmission_Count = bluetoothData[6:8] common.PSD_status = bluetoothData[8:9]
<html> <head> <style> /* The switch - the box around the slider */ .switch { position: relative; display: inline-block; width: 60px; height: 34px; } .switch input {display:none;} .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: green; -webkit-transition: .4s; transition: .4s; } .slider:before { position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px; background-color: white; -webkit-transition: .4s; transition: .4s; } input:checked + .slider { background-color: red; } input:focus + .slider { box-shadow: 0 0 1px #2196F3; } input:checked + .slider:before { -webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px); } /* Rounded sliders */ .slider.round { border-radius: 34px; } .slider.round:before { border-radius: 50%; } .grid-container { display: grid; grid-template-columns: auto auto; background-color: #2196F3; padding: 10px; } .grid-item { background-color: rgba(255, 255, 255, 0.8); border: 1px solid rgba(0, 0, 0, 0.8); padding: 20px; font-size: 30px; text-align: left; color: black } .hss-heading-font { font-family: "Arial", cursive, bold, sans-serif; font-size: 48px; color: blue; } </style> <script src = "/socket.io/socket.io.js"> </script> <script type=text/javascript src="http://code.jquery.com/jquery-3.3.1.min.js"></script> <script> var socket = io.connect(); socket.on("pinUpdate", handlePinUpdate); socket.emit('monitor', 'P8_11'); socket.emit('monitor', 'P8_14'); socket.emit('monitor', 'P8_15'); socket.emit('monitor', 'P8_16'); function handlePinUpdate(message) { var data = JSON.parse(message); if (data.pin == "P8_11") { if (data.value == 0) { document.getElementById("GarageDoor").checked = false; } else { document.getElementById("GarageDoor").checked = true; } } // End if (data.pin == "P8_11") if (data.pin == "P8_14") { if (data.value == 0) { document.getElementById("CarbonMonoxideSensor").checked = false; } else { document.getElementById("CarbonMonoxideSensor").checked = true; } } // End if (data.pin == "P8_14") if (data.pin == "P8_15") { if (data.value == 0) { document.getElementById("NaturalGasSensor").checked = false; } else { document.getElementById("NaturalGasSensor").checked = true; } } // End if (data.pin == "P8_15") if (data.pin == "P8_16") { if (data.value == 0) { document.getElementById("MotionSensor").checked = false; } else { document.getElementById("MotionSensor").checked = true; } } // End if (data.pin == "P8_16") } // End handlePinUpdate(message) function FunLivingRoomLight(){ var x = document.getElementById("LivingRoomLight").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"P8_9", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"P8_9", "value":1}'); } } function FunTV(){ var x = document.getElementById("TV").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"P8_10", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"P8_10", "value":1}'); } } function FunGarageDoor(){ var x = document.getElementById("GarageDoor").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"P8_11", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"P8_11", "value":1}'); } } function FunGasRange(){ var x = document.getElementById("GasRange").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"P8_12", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"P8_12", "value":1}'); } } function FunCarbonMonoxideSensor(){ var x = document.getElementById("CarbonMonoxideSensor").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"P8_14", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"P8_14", "value":1}'); } } function FunNaturalGasSensor(){ var x = document.getElementById("NaturalGasSensor").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"P8_15", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"P8_15", "value":1}'); } } function FunMotionSensor(){ var x = document.getElementById("MotionSensor").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"P8_16", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"P8_16", "value":1}'); } } function FunFrontDoorCamera(){ var x = document.getElementById("FrontDoorCamera").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"USR3", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"USR3", "value":1}'); } } function FunBackYardCamera(){ var x = document.getElementById("BackYardCamera").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"USR3", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"USR3", "value":1}'); } } </script> </head> <body> <div>Home Security System</div> <br><br> <div> <div>Living Room Light</div> <div> <label> <input id="LivingRoomLight" type="checkbox" onClick="FunLivingRoomLight();"> <span "grid-item"></span> </label> </div> <div>TV</div> <div> <label> <input id="TV" type="checkbox" onClick="FunTV();"> <span "grid-item"></span> </label> </div> <div>Garage Door</div> <div> <label> <input id="GarageDoor" type="checkbox" onClick="FunGarageDoor();"> <span "grid-item"></span> </label> </div> <div>Gas Range</div> <div> <label> <input id="GasRange" type="checkbox" onClick="FunGasRange();"> <span "grid-item"></span> </label> </div> <div>Carbon Monoxide Sensor</div> <div> <label> <input id="CarbonMonoxideSensor" type="checkbox" onClick="FunCarbonMonoxideSensor();"> <span "grid-item"></span> </label> </div> <div>Natural Gas Sensor</div> <div> <label> <input id="NaturalGasSensor" type="checkbox" onClick="FunNaturalGasSensor();"> <span "grid-item"></span> </label> </div> <div>Motion Sensor</div> <div> <label> <input id="MotionSensor" type="checkbox" onClick="FunMotionSensor();"> <span "grid-item"></span> </label> </div> <div>Front Door Camera</div> <div> <label> <input id="FrontDoorCamera" type="checkbox" onClick="FunFrontDoorCamera();"> <span "grid-item"></span> </label> </div> <div>Back Yard Camera</div> <div> <label> <input id="BackYardCamera" type="checkbox" onClick="FunBackYardCamera();"> <span "grid-item"></span> </label> </div>
Figure 12.
It uses the softwareSerial module instead of the hardware serial port for communicating with the Bluetooth module. SoftwareSerial uses pin 3 as the receive port and pin 4 for the transmit port. (Lines 1 & 2).
Lines 3-6 define the variables used to control the voltage to the MQ-7.
Lines 7-12 defines the rest of the variables for the sketch.
The setup code is contained in Lines 13-23. It initializes the serial ports. BTSerial is used to communicate with the Bluetooth module. I initialize the Serial port in case I want to add debug code. Line 16 clears the dataBuffer. Lines 17-20 waits for the BeagleBone Black to connect to the Bluetooth module, then reads the message sent from the BeagleBone Black (Line 21). Line 22 defines the DOUT Pin as an input pin.
The Loop function is contained in Lines 25-33. Line 26 calls the heating phase function, which sets the voltage to the sensor to 5 volts. Line 27 delays processing for 60 seconds. During this period the sensor clears itself of any particulates. Next the MeasurementPhase function is called, which sets the voltage to the sensor to 1.4 volts. It last for 90 seconds Line 29). When the measurement phase has ended the measurements are stored in COlimit and COvalue (Lines 30-31). COlimit is set to "1" if the threshold has been exceeded. COvalue contains the value of the measurement. Currently, the COvalue is not used. In Line 32, the SendStatus function is called. Then the cycle starts over.
Lines 34-40 initialized the dataBuffer.
Lines 42-45 sets the PWM for pin 10 to 255. This applies 5 volts to the sensor.
Lines 47-50 sets the PWM for pin 10 to 87. This applies 1.4 volts to the sensor. You may need to adjust this number to get 1.4 volts from your system.
Lines 52-64 sends a status to the BeagleBone Black. In Lines 56-63, the COlimit is checked. If it is 1 the threshold for the sensor was exceeded, the status is set to 1 and sent to the BeagleBone Black. Otherwise, the status is set to 0 and sent to the BeagleBone Black.
#include <SoftwareSerial.h> SoftwareSerial BTserial(3, 4); int heatTime = 60000; int measurementTime = 90000; int pwmPower = 87; int powerPin = 10; char dataBuffer[81]; String stringBuffer; const int AOUTpin=0; const int DOUTpin=8; int COlimit; int COvalue; void setup() { BTserial.begin(9600); Serial.begin(9600); ClearBuffer(); while (!BTserial.available()) { // Wait for a connected message from the HHS Controller } // if(!BTserial.available()) BTserial.readBytes(dataBuffer,80); pinMode(DOUTpin, INPUT); } // End setup() void loop() { HeatingPhase(); delay(heatTime); MeasurementPhase(); delay(measurementTime); COlimit = digitalRead(DOUTpin); COvalue = analogRead(AOUTpin); SendStatus(); } // End loop() void ClearBuffer() { for (int i = 0; i < 80; i++) { dataBuffer[i] = 0; } // End for (int i = 0; i < 80; i++) } // End ClearBuffer() void HeatingPhase() { analogWrite(powerPin, 255); } void MeasurementPhase() { analogWrite(powerPin, pwmPower); } void SendStatus() { // Source_Adapter_Id Destination_ Adapter_Id Max_Transmission_Count Status Data // 005 000 02 0/1 if (COlimit == 1) { BTserial.print("005000021$"); } else { BTserial.print("005000020$"); } } // End SendStatus()
Figure 13.
coSensorThread.py
The code for coSensorThread is described below (Figure 14).
Lines 1-6 import the required libraries.
Lines 7-21 contains the code for the co function. GPIO pin P8_14 is set to an output pin on Line 8.
Lines 10-21 contain the code for the loop. First, data is read from the CO Bluetooth device. If CO threshold was exceeded (common.CO_status == "1") and no previous alert was sent (common.coSensorStatus == "0") GPIO pin P8_14 is set to high (Line 12) and an alert is sent (Line 13). Whenever P8_14 is high coSensorStatus is set to "1". Otherwise, if the P8_14 is low and coSensorStatus is set to "1" the home owner has sent a request to send an all clear message (Line 18) and the coSensorStatus is set to "0".
import Adafruit_BBIO.GPIO as GPIO import time import common import parseData import processRequest import bluetoothSockets def co(socket): GPIO.setup("P8_14", GPIO.OUT) while(1==1): bluetoothSockets.ReceiveData(socket) if (common.CO_status == "1" and common.coSensorStatus == "0"): GPIO.output("P8_14", GPIO.HIGH) processRequest.CoSensor(common.CO_status) if GPIO.input("P8_14"): common.coSensorStatus = "1" else: if (common.coSensorStatus == "1"): processRequest.coSensor("0") common.coSensorStatus = "0" common.coSensorData = "" time.sleep(5)
Figure 14.
Section VI – Code for Gas Sensor
This section covers the code for the gas sensor.
gas-sensor-server.ino
The code for co-sensor-server is described below (Figure 15).
It uses the softwareSerial module instead of the hardware serial port for communicating with the Bluetooth module. SoftwareSerial uses pin 3 as the receive port and pin 4 for the transmit port. (Lines 1 & 2).
Lines 3-5 define the variables used to control the voltage to the MQ-4.
Lines 7-11 defines the rest of the variables for the sketch.
The setup code is contained in Lines 12-25. It initializes the serial ports. BTSerial is used to communicate with the Bluetooth module. I initialize the Serial port in case I want to add debug code. Line 16 clears the dataBuffer. Lines 17-20 waits for the BeagleBone Black to connect to the Bluetooth module, then reads the message sent from the BeagleBone Black (Line 21). Line 23 defines the DOUT Pin as an input pin. Line 24 calls the heating phase function, which sets the voltage to the sensor to 5 volts.
The Loop function is contained in Lines 27-32. Line 28 delays processing for 90 seconds. After 90 seconds have past the measurements are stored in COlimit and COvalue (Lines 29-30). COlimit is set to "1" if the threshold has been exceeded. COvalue contains the value of the measurement. Currently, the COvalue is not used. In Line 31 the SendStatus function is called. Then the cycle starts over.
Lines 33-39 initialized the dataBuffer.
Lines 40-43 sets the PWM for pin 10 to 255. This applies 5 volts to the sensor.
Lines 44-56 sends a status to the BeagleBone Black. In Lines 48-55, the COlimit is checked. If it is "1", the threshold for the sensor was exceeded, the status is set to "1" and sent to the BeagleBone Black. Otherwise, the status is set to "0" and sent to the BeagleBone Black.
#include <SoftwareSerial.h> SoftwareSerial BTserial(3, 4); int measurementTime = 90000; int pwmPower = 87; int powerPin = 10; char dataBuffer[81]; String stringBuffer; const int AOUTpin=0; const int DOUTpin=8; int COlimit; int COvalue; void setup() { BTserial.begin(9600); Serial.begin(9600); Serial.println("GAS Sensor Start"); ClearBuffer(); while (!BTserial.available()) { // Wait for a connected message from the HHS Controller } // if(!BTserial.available()) BTserial.readBytes(dataBuffer,80); pinMode(DOUTpin, INPUT); HeatingPhase(); } // End setup() void loop() { delay(measurementTime); COlimit = digitalRead(DOUTpin); COvalue = analogRead(AOUTpin); SendStatus(); } // End loop() void ClearBuffer() { for (int i = 0; i < 80; i++) { dataBuffer[i] = 0; } // End for (int i = 0; i < 80; i++) } // End ClearBuffer() void HeatingPhase() { analogWrite(powerPin, 255); } void SendStatus() { // Source_Adapter_Id Destination_ Adapter_Id Max_Transmission_Count Status Data // 006 000 02 0/1 if (COlimit == HIGH) { BTserial.print("006000021$"); } else { BTserial.print("006000020$"); } } // End SendStatus()
Figure 15.
gasSensorThread.py
The code for coSensorThread is described below (Figure 16).
Lines 1-6 import the required libraries.
Lines 7-21 contains the code for the gas function. GPIO pin P8_15 is set to an output pin on Line 8.
Lines 10-21 contain the code for the loop. First, data is read from the Gas Bluetooth device. If Gas threshold was exceeded (common.GAS_status == "1") and no previous alert was sent (common.gasSensorStatus == "0") GPIO pin P8_15 is set to high (Line 12) and an alert is sent (Line 13). Whenever P8_15 is high gasSensorStatus is set to "1". Otherwise, if the P8_15 is low and coSensorStatus is set to "1" the home owner has sent a request to send an all clear message (Line 18) and the gasSensorStatus is set to "0".
import Adafruit_BBIO.GPIO as GPIO import time import common import parseData import processRequest import bluetoothSockets def gas(socket): GPIO.setup("P8_15", GPIO.OUT) while(1==1): bluetoothSockets.ReceiveData(socket) if (common.GAS_status == "1" and common.gasSensorStatus == "0"): GPIO.output("P8_15", GPIO.HIGH) processRequest.CoSensor(common.GAS_status) if GPIO.input("P8_15"): common.gasSensorStatus = "1" else: if (common.gasSensorStatus == "1"): processRequest.gasSensor("0") common.gasSensorStatus = "0" common.gasSensorData = "" time.sleep(5)
Figure 16.
Section VII – Code for Electric Solenoid
range-sensor-server.ino
The range-sensor-server.ino sketch (Figure 17) turns the gas value on or off depending on the status received by the gasThread module. A status of "1" will turn the value on. A status of "0" will turn the value off.
It uses the softwareSerial module instead of the hardware serial port for communicating with the Bluetooth module. SoftwareSerial uses pin 3 as the receive port and pin 4 for the transmit port. (Lines 1 & 2).
Lines 3-5 defines the variables used.
Line 7 initializes the Bluetooth serial port.
Line 8 initializes the Arduino's serial port. If necessary it can be used as a debug port.
The Arduino pin that is attached to the electric solenoid value is set to output, on Line 9.
Line 10 initializes the data buffer.
Line 11 set pin 8 on the Arduino high.
Lines 12-15 waits for a message from the HSS Controller before continuing to the Loop function.
Line 16 read the "Welcome message" sent by the BeagleBone Black.
The sketch waits 5 seconds before continuing to the main loop (Line 17).
All the main loop does is calls the CheckForMessage function (lines 19-21).
The ClearBuffer function (Lines 22-28) sets the data buffer to nulls.
Lines 29-38 contain the code for the CheckForMessage function. If data is available (Line 31), the function reads the data, calls the ProcessRequest function to process the data, then clears the input buffer (Lines 33-36).
Lines 39-55 contains the code for the ProcessRequest function. It first verifies that the input (Line 43) is from the BeagleBone Black (Source_Adapter_Id = 000) and the input is for this Bluetooth device ( Destination_ Adapter_Id = 007).
If the status is "0" the ProcessRequest function will set the Arduino pin 8 low, which will turn the value off (Lines 45-48). If the status is "1" the ProcessRequest function will set the Arduino pin 8 high, which will turn the value on (Line 51).
#include <SoftwareSerial.h> SoftwareSerial BTserial(3, 4); char dataBuffer[81]; String stringBuffer; int pirPin = 8; // choose the input pin (for PIR sensor) void setup(){ BTserial.begin(9600); Serial.begin(9600); pinMode(pirPin, OUTPUT); // declare sensor as input ClearBuffer(); digitalWrite(pirPin,HIGH); while (!BTserial.available()) { // Wait for a connected message from the HHS Controller } // if(!BTserial.available()) BTserial.readBytes(dataBuffer,80); delay(5000); } // End setup() void loop(){ CheckForMessage(); } // End loop() void ClearBuffer() { for (int i = 0; i < 80; i++) { dataBuffer[i] = 0; } // End for (int i = 0; i < 80; i++) } // End ClearBuffer() void CheckForMessage() { if( BTserial.available()) { BTserial.readBytes(dataBuffer,80); stringBuffer = dataBuffer; ProcessRequest(); ClearBuffer(); } // End if( BTserial.available()) } // End CheckForMessage() void ProcessRequest() { // Source_Adapter_Id Destination_ Adapter_Id Max_Transmission_Count Status Data // 000 007 02 0/1 if(stringBuffer.substring(0,3) == "000" && stringBuffer.substring(3,6) == "007") { if(stringBuffer.substring(8,9) == "0") { digitalWrite(pirPin,LOW); } else { digitalWrite(pirPin,HIGH); } // End if(stringBuffer.substring(8,9) == "0") } // End if(stringBuffer.substring(0,3) == "000" && stringBuffer.substring(3,6) == "007") } // End ProcessRequest()
Figure 17.
rangeSensorThread.py contains the code that turns the gas range value on and off (Figure 18).
Lines 1-4 contains the required import statements.
Line 6 sets the GPIO pin P8_15 to input.
The program goes into a never ending loop at Line 7.
The program checks to see if the P8_15 pin is high (Line 8). If so, it sends the following data to range-sensor-server.ino (Line 10):
"000007021$"
// Source_Adapter_Id Destination_ Adapter_Id Max_Transmission_Count Status
// 000 007 02 1
Otherwise the pin is low, so it sends the follow data to range-sensor-server.ino (Line 12):
"000007020$"
// Source_Adapter_Id Destination_ Adapter_Id Max_Transmission_Count Status
// 000 007 02 0
The program will sleep for 5 seconds before continuing the loop (Line 14).
import Adafruit_BBIO.GPIO as GPIO import time import bluetoothSockets import processRequest def range(socket): GPIO.setup("P8_15", GPIO.IN) while(1==1): if GPIO.input("P8_15"): sendcount=socket.send("000007021$") else: sendcount=socket.send("000007020$") time.sleep(5)
Figure 18.
Have you ever wondered if a program exists on your Linux system? You can easily find out if it exists by using the which command. Say for example you want to know if python is installed on the system. Execute (Figure 19):
which python
It returns the path of the python executable.
How about bluetooth? We are using bluetooth. Execute:
which bluetooth
It returns nothing. That is because bluetooth is not a program, it is a package. To list packages you need to execute the dpkg command. Execute:
dpkg --list | grep 'bluetooth'
dpkg executes the display package program. --list is the list option which tells dpkg to display the packages it finds to the screen. The vertial bar (|) tells the command processor to take the output from the previous command (dpkg) and use it as input to the next command (grep). The grep command list all lines that contain the pharse bluetooth (Figure 19). I used the grep command because there are a lot of packages on the Linux system and using the grep command makes it easier to find what I am looking for. Execute dpkg --list to see what I mean.
You could do this in two lines if you wanted:
dpkg -list > dpkg.out
grep 'bluetooth' dpkg.out
The greater than sign (>) tells the command processor to put the output into a file called dpkg.out. It will create the file if it does not exist or overwrite everything in the file if the file does exist. To appeand to a file use two greater than signs (>>). Example: dpkg -list >> dpkg.out
Figure 19.
Have you ever accidentaly hit ctrl-Z? If you do, it puts the currently running program into the background. It is running, however it does not display on the screen. Let's say I am editing a file in my favorite editor, vi (Figure 20):
vi parseData.py
What if I accidently hit ctrl-Z? See Figure 21. To get the editor back I can enter fg (Figure 22). fg will put the program currently running in the background into the forground. I am now back into the vi editor (Figure 23).
Figure 20.
Figure 21.
Figure 22.
Figure 23.
Top Comments