Showing posts with label Scripting. Show all posts
Showing posts with label Scripting. Show all posts

Wednesday, November 09, 2022

Monitoring Sensors and Taking Action

I recently wrote a blog around using Microshift to run my Zigbee2MQTT workload. This blog described all the details on how to deploy Microshift and then deploy the components inside of Microshift to enable some home automation. Of course with Zigbee2MQTT there is an intuitive web interface to interact with the smart devices. However I wanted to take another approach that felt more realistic when it comes to edge use cases. I felt that in a industrial scenario there would be some code that would most likely subscribed and monitoring the MQTT queue. An action would be performed when a certain event was observed and the action itself might publish something into the MQTT queue. The rest of this blog will cover a simple scenario like I just described.

First we continue to use the same lab environment I used in my previous blog. The only difference here in the diagram below is we have now added a smart power outlet and a temperature/humidity sensor that can both be controlled remotely via the Zigbee protocol like all my other devices.

The Script

With my lab in place I decided I wanted ot write something in Perl. Some might think why use such an antiquated language like Perl and part of that is because I am old school. For my scenario I envisioned using the humidity sensor to detect when the humidity levels got too high. The threshold would then trigger an action on the event to turn on/off a dehumidifier plugged into the smart outlet. The basic process flow looks like the following diagram:

The script itself can take four different parameters:

  • --hostname: hostname or IP address of MQTT host (required)
  • --port: port for MQTT (optional but will default to 1883 if not provided)
  • --threshold: humidity value that determines when action should be taken
  • --help: prints the usage of script

The script itself is located here

When one runs the script without any flags the usage and an example will be displayed.

./mqtt-humidity.pl Usage: --hostname,-h Hostname or IP address of MQTT host --port,-p Port for MQTT (defaults to default 1883) --threshold,-t Threshold for humidity (defaults to 60) --help,-h Print this help Example: mqtt-humidity.pl -ho 10.43.26.170 -p 1883 -t 65

The Demonstration of Script

To demonstrate this script I went ahead and plugged in a light into my smart outlet which was in the off setting. I launched the script in a terminal window. Then I took the temperature/humidity sensor, cupped it in my hands and blew into my hands. The moisture in my breath is enough to temporarily raise the value. The script provides output so we can see the values changing and sure enough when I breathed into my hands with the sensor the value jumped to 81.37% which triggered the action event and turned on the light. I then set the sensor back on my desk and over the course of 5 minutes the value slowly receded. Once it dropped below the threshold value the light then turned back off. The output of my script run is below:

$ perl mqtt-humidity.pl -ho 10.43.26.170 -p 1883 -t 60 Temp C = 23.43 : Temp F = 74.174 : Humidity = 51.22 Temp C = 23.43 : Temp F = 74.174 : Humidity = 81.37 <-- Smart outlet turned on Temp C = 23.43 : Temp F = 74.174 : Humidity = 84.37 Temp C = 23.43 : Temp F = 74.174 : Humidity = 82.37 Temp C = 23.43 : Temp F = 74.174 : Humidity = 80.28 Temp C = 23.43 : Temp F = 74.174 : Humidity = 78.79 Temp C = 23.63 : Temp F = 74.534 : Humidity = 78.79 Temp C = 23.63 : Temp F = 74.534 : Humidity = 73.21 Temp C = 23.63 : Temp F = 74.534 : Humidity = 74.34 Temp C = 23.63 : Temp F = 74.534 : Humidity = 72.91 Temp C = 23.63 : Temp F = 74.534 : Humidity = 71.65 Temp C = 23.63 : Temp F = 74.534 : Humidity = 70.55 Temp C = 23.63 : Temp F = 74.534 : Humidity = 69.15 Temp C = 23.63 : Temp F = 74.534 : Humidity = 67.93 Temp C = 23.63 : Temp F = 74.534 : Humidity = 66.57 Temp C = 23.63 : Temp F = 74.534 : Humidity = 64.87 Temp C = 23.63 : Temp F = 74.534 : Humidity = 63.28 Temp C = 23.63 : Temp F = 74.534 : Humidity = 62.08 Temp C = 23.63 : Temp F = 74.534 : Humidity = 60.71 Temp C = 23.63 : Temp F = 74.534 : Humidity = 59.12 <-- Smart outlet turned off Temp C = 23.63 : Temp F = 74.534 : Humidity = 57.72 Temp C = 23.63 : Temp F = 74.534 : Humidity = 56.7 Temp C = 23.63 : Temp F = 74.534 : Humidity = 55.6 Temp C = 23.63 : Temp F = 74.534 : Humidity = 54.23 Temp C = 23.63 : Temp F = 74.534 : Humidity = 53.21 Temp C = 23.63 : Temp F = 74.534 : Humidity = 52.14 Temp C = 23.63 : Temp F = 74.534 : Humidity = 51.05 Temp C = 23.63 : Temp F = 74.534 : Humidity = 50.04 Temp C = 23.22 : Temp F = 73.796 : Humidity = 50.04 Temp C = 23.22 : Temp F = 73.796 : Humidity = 50.04 ^C

Now this was a very simple example but imagine the possibilities. For example what if this was a greenhouse that needed to keep the humidity and/or even the temperature at a certain range. If the device that reduces the humidity/temperature (dehumidifier -or- exhaust fan) in the greenhouse could take Zigbee commands directly and control the speed of operation we might be able to not only turn it on/off but also increase/decrease speed of operation. All of this ensures that whatever was growing in the greenhouse is not damaged and also ensures we are powering devices only when we need to have them powered. The bottom line is it saves businesses like the greenhouse operational costs when they are operating efficiently.

Friday, January 02, 2015

Powersearch Old Files with Bash Waste Script


Waste is a simple script that makes it easier to search for old files in a path on a linux systems.   Waste features allow you do display the listing sorted by day or size and search for files a specific number of days old or between a range of days old.    It simplifies the usage of the find command by wrapping it up into a easy to use script.   Its appeal is as a cleanup script for directories that have files that need to be purged over time.

#!/bin/bash
if [[ $# = 0 || $1 = "-h" || "$#" -lt 4 ]]; then
        echo "Usage: [-d|-s] [-r {start end}|-o {start}] directory"
        echo " -h displays the help"
        echo " -d display listing sorted by day"
        echo " -s display listing sorted by size"
        echo " -r display files between a specific number of days old"
        echo " -o display files older then a specific number of days"
        echo " Example1: waste -d -r 10 20 /home"
        echo " Example2: waste -s -o 30 /process"
        exit
fi
case "$1" in
        '-s')
                case "$2" in
                        '-r')
                                if [ "$#" -lt 5 ]; then
                                        echo "Usage: [-d|-s] [-r {start end}|-o {start}] directory"
                                        exit
                                fi
                                printf "Date\t\tSize\tDirectory/File\n"
                                /usr/bin/find $5 -type d -daystart -mtime +$3 -mtime -$4 -printf "%CY-%Cm-%Cd\t" -maxdepth 1 -exec /usr/bin/du.new -s --block-size=M "{}" \; | /bin/sort -k2nr
                                ;;
                        '-o')
                                if [ "$#" -lt 4 ]; then
                                        echo "Usage: [-d|-s] [-r {start end}|-o {start}] directory"
                                        exit
                                fi
                                printf "Date\t\tSize\tDirectory/File\n"
                                /usr/bin/find $4 -type d -daystart -mtime +$3 -printf "%CY-%Cm-%Cd\t" -maxdepth 1 -exec /usr/bin/du.new -s --block-size=M "{}" \; | /bin/sort -k2nr
                                ;;
                esac
        ;;
        '-d')
                case "$2" in
                        '-r')
                                if [ "$#" -lt 5 ]; then
                                        echo "Usage: [-d|-s] [-r {start end}|-o {start}] directory"
                                        exit
                                fi
                                printf "Date\t\tSize\tDirectory/File\n"
                                /usr/bin/find $5 -type d -daystart -mtime +$3 -mtime -$4 -printf "%CY-%Cm-%Cd\t" -maxdepth 1 -exec /usr/bin/du.new -s --block-size=M "{}" \; | /bin/sort -k2nr | /bin/sort
                                ;;
                        '-o')
                                if [ "$#" -lt 4 ]; then
                                        echo "Usage: [-d|-s] [-r {start end}|-o {start}] directory"
                                        exit
                                fi
                                printf "Date\t\tSize\tDirectory/File\n"
                                /usr/bin/find $4 -type d -daystart -mtime +$3 -printf "%CY-%Cm-%Cd\t" -maxdepth 1 -exec /usr/bin/du.new -s --block-size=M "{}" \; | /bin/sort -k2nr | /bin/sort
                                ;;
                esac
        ;;
esac 

Wednesday, October 09, 2013

PowerShell & Isilon's REST API: Part 3 Creating Folder


In my previous posts I dabbled with Isilon's REST API and Perl.   In the following I provide an example of how to create a folder on the Isilon cluster using the REST API via PowerShell.   I have to say I am starting to like PowerShell, but I still have a lot of learning to do before I will feel as comfortable as I do in Perl.

The following example connects to the Isilon cluster and creates the folder schmaus101 in the following namespace path: /namespace/ifs/data/benz/.

### Ignore SSL Cert Errors ###
add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
    public class IDontCarePolicy : ICertificatePolicy {
    public IDontCarePolicy() {}
    public bool CheckValidationResult(
        ServicePoint sPoint, X509Certificate cert,
        WebRequest wRequest, int certProb) {
        return true;
    }
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = new-object IDontCarePolicy
### Username & Password ###
$username = 'admin'
$upassword = 'password'
### Build Up Authentication String ###
$auth = $username + ':' + $upassword
$Encoded = [System.Text.Encoding]::UTF8.GetBytes($auth)
$EncodedPassword = [System.Convert]::ToBase64String($Encoded)
### Build Up HTTP Headers ###
$headers = @{}
#$headers."Accept" = "application/json"
$headers."Authorization"="Basic $($EncodedPassword)"
$headers."x-isi-ifs-target-type" = "container"
### Base HTTP URL ###
$baseurl = 'https://10.88.82.106:8080'
$resource = '/namespace/ifs/data/benz/schmaus101'
$url = $baseurl + $resource
### Run REST PUT to Create Directory ###
$dir = Invoke-RestMethod -Uri $url -Headers $headers -Method Put -ContentType "application/json"

Once the folder is created, one could go back and add a size quota and share off of the folder to complete the automation provisioning sequence.  However I will cover those in my next PowerShell musing post.

Monday, October 07, 2013

Perl and Isilon's REST API: Part 2 Creating Directory

In my last post you saw how I was able to do a directory listing on an Isilon cluster using the Isilon REST API.   In this posting I am providing an example of how you can create a directory on the Isilon cluster using the Isilon REST API.

The simple script below shows how I can create the directory schmaus8 (as an example) under the /ifs/data path on the cluster:
use REST::Client;
use JSON;
use Data::Dumper;
use MIME::Base64;
use IO::Socket::SSL qw( SSL_VERIFY_NONE );
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0;
my $username = 'admin';
my $password = 'password$';
my $headers = {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password), 'x-isi-ifs-target-type' => 'container'};
my $client = REST::Client->new();
$client->getUseragent()->ssl_opts( SSL_verify_mode => 0 );
$client->setHost('https://10.88.82.106:8080');
$client->PUT('/namespace/ifs/data/schmaus8','schmaus8',$headers);
print $client->responseContent(). "\n"; ;
exit;

The output if successful from the script above will be nothing:

C:\TEMP>perl isi-file-create.pl
C:\TEMP>

This script could be altered to provide input for the path you need to have created.  You could also join the previous script I provided to first check and see if the directory exists before you try to create it.

Monday, August 15, 2011

Determine Core Count on Solaris 10 Hosts


This question always comes up time and time again. How does one figure out how to get the correct core count on a Solaris 10 host?  Below is the one line answer:

echo "`hostname` has `kstat cpu_info |grep core_id|uniq|wc -l` cores"

Wednesday, January 24, 2007

Script to Check StorEdge 3510 Disk Status


This little script will run the sccli utility and report out the disk status from the Sun Microsystems StorEdge 3510.
#!/usr/local/bin/zsh ################################################################# # This script checks 3510 status # ################################################################# EMAILADDR="sysadmin@software.umn.edu" FAILSTAT="0" FAILSTAT1="0" for DISKS in `/usr/local/sccli/sbin/sccli -l|/usr/local/bin/cut -d" " -f1 -` do SCCLI=`/usr/local/sccli/sbin/sccli $DISKS show logical-drives 2>&1 > /tmp/lds.out` LDS=`/usr/local/bin/cat /tmp/lds.out 2>&1|grep ld|grep -v Good` if [ $? = 1 ]; then FAILSTAT="0" else FAILSTAT1="1" fi SCCLI=`/usr/local/sccli/sbin/sccli $DISKS show enclosure-status 2>&1 > /tmp/sccli.out` for TESTS in Topology Fan PS Temp Voltage DiskSlot do CHECK=`/usr/local/bin/cat /tmp/sccli.out 2>&1|grep $TESTS|grep -v OK` if [ $? = 1 ]; then FAILSTAT="0" else FAILSTAT1="1" fi done if [ $FAILSTAT1 = 1 ]; then MERGE=`/usr/local/bin/cat /tmp/sccli.out>/tmp/report.out` MERGE=`echo>>/tmp/report.out` MERGE=`/usr/local/bin/cat /tmp/lds.out>>/tmp/report.out` SYSTEM=`hostname` SUBJECTLINE="StoreEdge Error -- HOST: $SYSTEM DISK: $DISKS" /bin/mailx -s $SUBJECTLINE $EMAILADDR < /tmp/report.out fi done exit

Script to Check Solaris DiskSuite States


This Kourne shell script will check for any errors on metadevices with Disksuite on Solaris.

#!/bin/ksh
#########################################################################
# check_disks - check metadevices for errors and alert the user. #
# USAGE: check_disks [ -m (address) ] #
#########################################################################
TZ=CST5CDT
SUBJECT="MetaDisk Errors on `uname -n`"
GREP_CMD="/bin/egrep"
GREP_ARG="-s"
METASTAT_CMD=/usr/opt/SUNWmd/sbin/metastat
METADB_CMD=/usr/opt/SUNWmd/sbin/metadb
DISKSUITE_PRESENT=1
MAIL_OUTPUT=''
MAIL_RECIP=''
DEFAULT_MAIL_RECIP=''
OUTPUT_MSG=""
RESULT=''
OUTPUT_CODE=0
#########################################################################
# FUNCTION DEFINITIONS #
#########################################################################
function error_out {
   RETURN_CODE=$2
   ERROR_MSG=$1
   print - $ERROR_MSG
   exit $RETURN_CODE
}
#########################################################################
# MAIN PROGRAM #
#########################################################################
while getopts :m: c
do
case $c in
   m ) MAIL_OUTPUT="YES" # any non-null string will do
   MAIL_RECIP=$OPTARG
   if [[ -z $MAIL_RECIP ]]
   then
      MAIL_RECIP=$DEFAULT_MAIL_RECIP
   fi
  ;;
  ?) error_out "Usage: check_disks [ -m mail_addr ]" 1
  ;;
esac
done
if [ ! -x $GREP_CMD ]
then
   GREP_CMD="/usr/xpg4/bin/egrep"
fi

if [ ! -x $GREP_CMD ]
then
   print "ERROR: egrep not executable or not found"
   exit 1
fi
PATH=$PATH:/usr/sbin
METASTAT_BIN=$(/bin/which metastat)
if [ ! -x $METASTAT_CMD ]
   then
   if [ -x $METASTAT_BIN ]
   then
      METASTAT_CMD=$METASTAT_BIN
      DISKSUITE_PRESENT=1
   else
      DISKSUITE_PRESENT=0
   fi
fi
METADB_BIN=$(/bin/which metadb)
if [ ! -x $METADB_CMD ]
then
   if [ -x $METADB_BIN ]
   then
      METADB_CMD=$METADB_BIN
      DISKSUITE_PRESENT=1
   else
      DISKSUITE_PRESENT=0
   fi
fi
if [[ $DISKSUITE_PRESENT -eq 0 ]]
then
   error_out "DiskSuite has been found." 3
fi
#################################################################
# DISKSUITE SECTION #
#################################################################
if [ $DISKSUITE_PRESENT -ne 0 ]
then
   $METASTAT_CMD | $GREP_CMD $GREP_ARG aint
   if [ $? -eq 0 ]
   then
      OUTPUT_MSG="${OUTPUT_MSG}Disk requires maintenance on `uname -n`\n"
   fi
   $METASTAT_CMD | $GREP_CMD $GREP_ARG "In use"
   if [ $? -eq 0 ]
   then
      OUTPUT_MSG="${OUTPUT_MSG}Disk hot spared on `uname -n`"
   fi
   $METADB_CMD | $GREP_CMD $GREP_ARG "[A-Z]"
   if [ $? -eq 0 ]
   then
      OUTPUT_MSG="${OUTPUT_MSG}Metadb problems on `uname -n`\n"
   fi
fi
#################################################################
# OUTPUT SECTION #
#################################################################
if [[ ! -z $MAIL_OUTPUT ]]
then
   if [[ ! -z "$OUTPUT_MSG" && ! -z $MAIL_RECIP ]]
   then
      print $OUTPUT_MSG | mailx -s "$SUBJECT" $MAIL_RECIP
      OUTPUT_CODE=-1
   fi
   else
   if [[ ! -z "$OUTPUT_MSG" ]] # or else just print on stdout
   then
      print $OUTPUT_MSG
      OUTPUT_CODE=-1
   fi
fi
return $OUTPUT_CODE