Hello Everyone,
As always, I make plans to do one thing and end up doing another. The Carbon Monoxide and Natural Gas sensors I had were not breadboard friendly. Therefore, I decided to order the newer breadboard friendly versions of the sensors. While I was waiting for the sensors I implemented the second power relay switch and the garage door sensor.
The implementation of the second power relay switch was easy since the logic for the second power relay switch was the same as the first power relay switch. It was the implementing the garage door sensor that took the bulk of my time. I had to make changes to the hss.html and hss.js files to accommodate the logic for the garage door sensor. Also, I had to create the logic to handle the garage door sensor and to interface with the BeagleBone Black. I created an electronic switch to open/close the garage door via garage door opener connected to the BeagleBone black. Being that I am not an electronics guru it took some time to figure out how to use a transistor as an electronic switch.
The details for adding the second Light Smart Plug and the Garage Door Sensor, to the Home Security System, are given in the sections below:
Section I – GPIO Pin Assignments
Section II – Smart Plug Design
Section III – Smart Plug Code
Section IV – Garage Door Sensor Design
Section V – Garage Door Sensor Code
Section VI – Linux Tips
There is not much time left, So I need to start working on implementing the Carbon Monoxide sensor, Natural Gas Sensor, and the Cameras.
Talk to you soon.
Quote of the Moment -
It ain’t over until it’s over.
-- Yogi Berra
Previous Bluetooth Challenge Home Security System Posts |
Bluetooth Challenge - Home Security System - Blog Post VIII |
Section I - GPIO Pin Assignments
Here are the current GPIO pin assignments.
P8_9 | Living Room Light |
P8_10 | TV |
P8_11 | Garage Door |
P8_12 | Gas Range |
P8_14 | Carbon Monoxide Sensor |
P8_15 | Natural Gas Sensor |
P8_16 | Motion Sensor |
P8_17 | Garage Door Opener |
Section II - Smart Plug Design
I only made two minor changes to the design to implement the second smart plug. I changed the name for the python file from light1Thread.py to lightThread.py (Figure 1). I also renamed the function to light1 and added the function for the second smart plug, light2.
Figure 1.
Section III – Smart Plug Code
This section covers the code for the second power relay switch and code changes made to enhance the thread processing.
light-server-2.ino
The code for the second power relay switch (Light-server-2.ino) is the same as the code for the first one, except for the following change (Figure 2):
The Destination_ Adapter_Id in Line 52 is now 003.
#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(10000); } // 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 003 02 0/1 if(stringBuffer.substring(0,3) == "000" && stringBuffer.substring(3,6) == "003") { 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) == "003") } // End ProcessRequest()
Figure 2.
hss-controller.py
The main changes made to the hss-controller included adding the logic for the second power relay switch and the garage door sensor (Figure 3).
Line 6 was changed from light1Thread to lightThread.
The Bluetooth addresses for the second power relay switch and the garage door sensor were added on Lines 12-13.
The thread name for the PIR Sensor was change to t1 in Lines 18-19.
The thread name for the first power relay switch was changed to t2 in Lines 24-25.
Lines 27-30 create and connect to the socket for the second power relay switch. The thread for the second power relay switch is also started.
Lines 32-35 create and connect to the socket for the garage door sensor. The thread for the garage door sensor is also started.
import time from threading import Thread import alert import bluetoothSockets import pirSensorThread import lightThread import garageThread 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 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() while (1 == 1): time.sleep(10)
Figure 3.
lightThread.py
Lines 17-26 were added for the second power relay switch function(Figure 4). The only difference from the light1 is the pin number. It uses P8_10 instead of P8_9.
import Adafruit_BBIO.GPIO as GPIO import time import bluetoothSockets import processRequest def light1(socket): GPIO.setup("P8_9", GPIO.IN) while(1==1): if GPIO.input("P8_9"): sendcount=socket.send("000002021$") print "P8_9 is HIGH" else: sendcount=socket.send("000002020$") print "P8_9 is LOW" time.sleep(5) def light2(socket): GPIO.setup("P8_10", GPIO.IN) while(1==1): if GPIO.input("P8_10"): sendcount=socket.send("000003021$") print "P8_10 is HIGH" else: sendcount=socket.send("000003020$") print "P8_10 is LOW" time.sleep(5)
Figure 4.
bluetoothSockets.py
There were several changes made to the bluetoothSockets python code. The changes were made so that threads can share data and to make sure one thread's data is not overridden by another thread's data. The changes are as follows (Figure 5):
Line 3 contains the import statement for the common.py file. common.py contains the data that is shared between threads.
Line 4 contains the code to parse the data sent by the Bluetooth modules.
Extensive changes were made to the ReceiveData function, Lines 14-28. Line 18 contains a switch to determine when all of the data as been received from a give Bluetooth module. Lines 20-28 are executed until all of the data as been received from a given Bluetooth module. Data from the Bluetooth module is put into the receiveBuffer (Line 20). Data is accumulated into the bluetoothdata buffer (Line 21) until a "$" is received in the receiveBuffer (Line 22). The dataNotReceived switch is set to "false" so that received data can be parsed (Line 27) and populated into the appropriate Bluetooth data variable (Line 28).
Lines 30-37 populate the received Bluetooth data into the appropriate Bluetooth data variable. If the received source_Adapter_Id is "001" the received Bluetooth data is parsed into the variables for the PIR sensor (Lines 32-34). If the received source_Adapter_Id is "004" the received Bluetooth data is parsed into the variables for the PIR sensor (Lines 35-37).
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 = "" dataNotReceived = True while (dataNotReceived): receiveBuffer = socket.recv(80) bluetoothData = bluetoothData + receiveBuffer if (receiveBuffer.endswith("$")): dataNotReceived = False if (dataNotReceived): x = 1 // Does Nothing 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
Figure 5.
common.py
common.py contains the variables that are shared between threads (Figure 6).
Lines 1-4 contain the fields passed from the Bluetooth module. Note that currently max_Transmission_Count is not used since the Bluetooth modules implemented so far are close enough to the BeagleBone Black to pass the data in one hop.
Lines 6-9 contain the fields passed from the Garage Door Bluetooth module.
Lines 11-14 contain the fields passed from the PIR Sensor Bluetooth module.
Lines 16-19 contain the data passed by Bluetooth modules. Putting the data from a given Bluetooth module in its own variables allows the ReceiveData function to read incoming data while the current data is processed.
Line 21 is used by the PIR Sensor function.
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 = "" pirSensorData = "" lightSwitch1Data = "" lightSwitch2Data = "" garageDoorData = "" pirSensorStatus = 0
Figure 6.
parseData.py
parseData.py separates the data received from the Bluetooth modules into the appropriate variables (Figure 7).
Any time data is received by the ReceiveData function is calls the parseBluetoothData function (Lines 3-7).
If the ReceiveData function reads data from the Garage Door module it calls the parseGarageDoorData function. garageThread.py uses these fields instead of the fields from the parseBluetoothData function so that the ReceiveData function can immediately process the next Bluetooth transmission (Lines 9-14).
If the ReceiveData function reads data from the PIR Sensor module it calls the parsePirSensorData function. pirSensorThread.py uses these fields instead of the fields from the parseBluetoothData function so that the ReceiveData function can immediately process the next Bluetooth transmission (Lines 17-21).
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] common.garageDoorData = bluetoothData 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]
Figure 7.
pirSensorThread.py
pirSensorThread.py was changed to use the data from the common.py file (Figure 8).
Line 2 was added to import the data from the common.py file.
Lines 10-12, 15, 17, 19-20 now pulls its variable data from the common file.
import Adafruit_BBIO.GPIO as GPIO import common import processRequest import bluetoothSockets def pir(socket): GPIO.setup("P8_16", GPIO.OUT) while (1 == 1): bluetoothSockets.ReceiveData(socket) if (common.PSD_status != "H"): if (common.PSD_status == "1"): processRequest.PirSensor(common.PSD_status) if GPIO.input("P8_16"): print "Do Nothing" common.pirSensorStatus = "1" else: if (common.pirSensorStatus == "1"): processRequest.PirSensor("0") common.pirSensorStatus = "0" common.pirSensorData = ""
Figure 8.
Section IV – Garage Door Sensor Design
The design for the Garage Door Sensor is basically the same as the other modules (Figure 9). There are some differences. The Arduino Pro Trinket polls the sonar Sensor (HC-04) every ten seconds and sends the status to the BeagleBone Black (Figure 10). The other difference is that there is a garage door opener attached to the BeagleBone Black (Figure 11 & 11A). It is attached to the breadboard with Velcro straps. The garage door opener is controlled by an electronic switch built with a 2N2222 transistor. Note the use of a 2.7k resistor (Figure 11A). Without it, the transistor may overheat and fail. The HC-04 is attached to the garage ceiling. The HC-04 has a beam width of 15 degrees which allows me to place the sensor close to the door opening. Placing the sensor close to the garage door opening helps ensure the garage door is closed when the sensor is triggered. I placed the breadboard on top of the garage door motor (Figure 12).
Figure 9.
Figure 10.
Figure 11.
Figure 11A.
Figure 12.
Section V – Garage Door Sensor Code
garage-door-server.ino
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 & 42).
NewPing.h is a library used to process data from the HC-04. The library allows you to use the same pin for the trigger pin and the echo pin (Lines 6-8).
Line 8 defines the maximum distance, in centimeters that the sensor will detect an object.
Line 9 creates the sonar object.
Lines 12-15 defines the variables for the sketch.
The setup code is contained in Lines 17-31. 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 21 clears the dataBuffer. Lines 23-28 waits for the BeagleBone Black to connect to the Bluetooth module. Line 29 waits ten seconds before continuing. This is the amount of time it takes for my garage door to open or close.
Lines 33-39 contains the code for the main loop. Line 35 gets the distance to the nearest object (garage door or floor) and line 36 calls the SendStatus function which sends the status (open or closed) of the door, to the BeagleBone Black. Line 37 waits ten seconds before continuing.
The ClearBuffer function (Lines 41-47) sets the data buffer to nulls.
Lines 49-67 contains the code to read the sonar sensor. Line 52 gets the current distance from the nearest object. Lines 54-57 sets the distance to 100cm, if the distance read from the sonar sensor is out of range.
Lines 59-66 adds the status of the garage door (open or closed) to the door variable. If the distance of the nearest object is greater than 61cm the door is considered open. Otherwise, the door is considered closed.
Lines 69-81 sends the status of the door to the BeagleBone Black. If the door variable equals "open" a status of one is sent. Otherwise, a status of zero is sent.
#include <SoftwareSerial.h> #include <NewPing.h> SoftwareSerial BTserial(3, 4); #define TRIGGER_PIN 8 #define ECHO_PIN 8 #define MAX_DISTANCE 400 NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); char dataBuffer[81]; String stringBuffer; float distance; String door; 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); delay(10000); } // End setup() void loop(){ GetUltrasonicDistance(); SendStatus(); delay(10000); } // 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 GetUltrasonicDistance() { distance = sonar.ping_cm(); if (distance == 0) { distance = 100; } if (distance > 61) { door = "open"; } else { door = "closed"; } } // End GetUltrasonicDistance() void SendStatus() { // Source_Adapter_Id Destination_ Adapter_Id Max_Transmission_Count Status Data // 004 000 02 0/1 if (door == "open") { BTserial.print("004000021$"); } else { BTserial.print("004000020$"); } } // End SendStatus()
Figure 13.
garage-door-server.ino
Lines 1-5 contains the required imports statements.
Lines 7-18 contains the code for the garageDoor function.
Line 8 sets GPIO pin P8_11 to output. Pin P8_11 set high if the status field is one or set to low if the status field is zero (Lines 14-17).
Line 9 initializes the GPIO pin P8_17 to output. Line 10 sets pin P8_17 to low. Pin P8_17 is attached to the garage door opener. If set to high it will open or close the garage door. Pin P8_17 is changed by the web server (hss.js).
Line 13 retrieves the Bluetooth record.
Line 18 resets the garageDoorData variable to null.
Line 19 waits five seconds before continuing.
import Adafruit_BBIO.GPIO as GPIO import time import bluetoothSockets import common import pa def garageDoor(socket): GPIO.setup("P8_11", GPIO.OUT) GPIO.setup("P8_17", GPIO.OUT) GPIO.output("P8_17", GPIO.LOW) while(1==1): bluetoothSockets.ReceiveData(socket) if (common.GDD_status == "1"): GPIO.output("P8_11", GPIO.HIGH) else: GPIO.output("P8_11", GPIO.LOW) common.garageDoorData = "" time.sleep(5)
Figure 14.
hss.js
hss.js is a JavaScript program (Figure 10). This is the web server code that communicates with the web browser and the BeagleBone Black.
There is only one change in hss for the garage door:
In Lines 44-50, if the home owner presses the Garage Door button in the web browser, the P8_17 is set to high for a half a second, then set back to low. This will either open or close the garage door via the garage door opener that is attached to the BeagleBone Black.
var app = require('http').createServer(handler); var io = require('/usr/local/lib/node_modules/bonescript/node_modules/socket.io').listen(app); var fs = require('fs'); var bb = require('bonescript'); const spawn = require('child_process').spawn; var htmlPage = '/home/debian/HSS/hss.html'; // use this for Debian var pinStates = {}; var soc; app.listen(9090); function handler (req, res) { fs.readFile(htmlPage, function (err, data) { if (err) { res.writeHead(500); return res.end('Error loading file: ' + htmlPage); } res.writeHead(200); res.end(data); }); } function onConnect(socket) { socket.on('digitalWrite', handleDigitalWrite); socket.on('monitor', handleMonitorRequest); soc = socket; } function handleMonitorRequest(pin) { bb.pinMode(pin, bb.INPUT); pinStates[pin] = 0; } function handleDigitalWrite(message) { var data = JSON.parse(message); //const pythonProcess = spawn('python2.7', ['webRequest.py', data.pin, data.value]); bb.pinMode(data.pin, bb.OUTPUT); bb.digitalWrite(data.pin, data.value); if (data.pin == "P8_11") { bb.pinMode("P8_17", bb.OUTPUT); bb.digitalWrite("P8_17", 1); pause(500); bb.digitalWrite("P8_17", 0); } } function checkInputs() { for (var pin in pinStates) { var oldValue = pinStates[pin]; var newValue = bb.digitalRead(pin); if (oldValue != newValue) { soc.emit("pinUpdate", '{"pin":"' + pin + '", "value":' + newValue + '}'); pinStates[pin] = newValue; } } } function pause(milliseconds) { var dt = new Date(); while ((new Date()) - dt <= milliseconds) { /* Do nothing */ } } io.sockets.on('connection', onConnect); setInterval(checkInputs, 500);
Figure 15.
hss.html
hss.html contains the HTML and JavaScript code to display and modify the web browser. Only three changes were made to hss.html:
Line 93, which tells the web servers to monitor GPIO pin P8_11 for changes.
Lines 97-107 were added to handle any changes in the pin status for P8_11. If the pin is changed to low (0), the GarageDoor element will be changed to unchecked and its button is set to red. If the pin is high (1) the element will be changed to checked and its button is set to green.
In lines 53 and 57, "USR3: is changed to P8_11.
<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_16'); socket.emit('monitor', 'P8_11'); 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_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":"USR3", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"USR3", "value":1}'); } } function FunCarbonMonoxideSensor(){ var x = document.getElementById("CarbonMonoxideSensor").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"USR3", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"USR3", "value":1}'); } } function FunNaturalGasSensor(){ var x = document.getElementById("NaturalGasSensor").checked; if(x == false) { socket.emit('digitalWrite', '{"pin":"USR3", "value":0}'); } else { socket.emit('digitalWrite', '{"pin":"USR3", "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 16.
Section VI –Unix Tips
One of the commands that I use quite a bit is the find command. To get it to do what I want it to, I use several options. I like the find command however, I get tired of keying in the options for the command. I tried saving the command in a file and copying and pasting it on the command line. However, that also takes too long for me. So I wrote a one line shell program to execute the command for me.
Here is an example of the find command I use:
sudo find . -depth -name *file-to-search-for* -print
I use the sudo command because I often search directories that require root access.
There is a period after the find command. The period tells the find command to start searching in the current directory.
The -depth option tells the find command to search all of the sub-directories.
The -name specifies the name of the file to search for. The string after the -name option tells the find command what to search for. The putting asterisks (*) before and after the file-to-search-for tells the find command to search for anything and contains the string in between the asterisks.
The -print option tells the find command to display the full path name of the results.
All you need to do is create a file and add the line below to the file.
sudo find . -depth -name "*$1*" -print
The $1 in the string "*$1*" tells the shell to replace the $1 with the first parameter on the command line. Note that the command itself is considered the 0th parameter. Therefore you can access the name of your shell program by using $0.
Also, you need to make it executable. Enter, at the command line (I called my shell program findit ):
chmod 755 findit
This will make the file read/write/executable by the owner and read/executable by everyone else (figure 17).
Example of a search using the findit shell program:
If I enter, on the command line (Figure 18):
. findit Data
I get the results shown in Figure 18. Remember I need the period followed by a space before the program name, since the program is in the current directory.
Figure 17.
Figure 18.
Top Comments