0

I recently bought a Slice of Radio - https://www.wirelessthings.net/slice-of-radio-wireless-rf-transciever-for-the-raspberry-pi, which I connected to my serial port in an RPi with Raspbian.

I have a temperature+humidity sensor which connects to the Slice of Radio and periodically sends a string of characters with several information, which can be read in the RPi from the serial port (/dev/ttyAMA0).

To read this information and make use of it, I decided to write a Bash script. This information is transmitted concatenated with 12-char strings and each string always starts with a fixed set of characters (in the case, aSD).

This Bash script is supposed to be running in an infinite loop, to make sure that all the information that is sent periodically, is captured and processed as it should.

For that purpose, the following small script works properly:

    #!/bin/bash
    IFS='aSD'
    while read -r -n 12 char1 char2 char3 char4 char5
    do
    date=`/bin/date -u +%F@%X`
    echo $date
    echo  "1= ""$char1"
    echo  "2= ""$char2"
    echo  "3= ""$char3"
    echo  "4= ""$char4"
    echo  "5= ""$char5"
    done < /dev/ttyAMA0

and outputs the following (every line 4 is the information I need):

    2016-02-13@23:06:12
    1= 
    2= 
    3= 
    4= RHUM77.0-
    5= 
    2016-02-13@23:06:12
    1= 
    2= 
    3= 
    4= TEMP20.0-
    5= 
    2016-02-13@23:11:08
    1= 
    2= 
    3= 
    4= RHUM77.0-
    5= 
    2016-02-13@23:11:08
    1= 
    2= 
    3= 
    4= TEMP19.9-
    5= 
    2016-02-13@23:11:08
    1= 
    2= 
    3= 
    4= BATT3.32-
    5= 
    2016-02-13@23:11:08
    1= 
    2= 
    3= 
    4= 
    5= LEEPING-

Still then, if I run the following script (a simplified version of mine):

    !/bin/bash
    log_file="/home/pi/logs/Temp_$(date +%Y%m%d).log"
    log_file_copy="/home/pi/logs/Temp_$(date +%Y%m%d)_copy.log"
    sensor="/home/pi/sensor"

    IFS='aSD'
    while read -r -n 12 char1 char2 char3 value char5
    do
    date=`/bin/date -u +%F@%X`
    msgid=$( /bin/echo $value | cut -c1-4 )
    echo $msgid
    if [ "$msgid" = "TEMP" ]; then

    #Write current temperature to log file
    log=`/bin/date -u +%F@%X`
    log+=" | Current Temperature: "
    temp=$( /bin/echo $value | cut -c5-8 )
    log+=$temp
    log+=" ºC"
    /bin/echo $log>>$log_file
    elif [ "$msgid" = "RHUM" ]; then

    #If log file backup still exists, start by deleting it
    if [ -f "$log_file_copy" ]; then
            /bin/rm $log_file_copy > /dev/null 2>&1 &
    fi
    #If log file already exists, start by creating a backup
    if [ -f "$log_file" ]; then
            /bin/mv $log_file $log_file_copy > /dev/null 2>&1 &
    fi

    #Write current relative humidity to log file
    log=`/bin/date -u +%F@%X`
    log+=" | Current Relative Humidity: "
    rhum=$( /bin/echo $value | cut -c5-8 ) 
    log+=$rhum
    log+=" %"
    /bin/echo $log>>$log_file
    elif [ "$msgid" = "BATT" ]; then

    #Write current battery voltage to log file
    log=`/bin/date -u +%F@%X`
    log+=" | Current Battery Voltage: "
    volt=$( /bin/echo $value | cut -c5-8 )
    if [ "$volt" != "LOW-" ]; then
            volt="LOW"
            log+=$volt
    else
            log+=$volt
            log+=" V"
    fi
    /bin/echo $log>>$log_file
    fi

    #Store values to display in website - personal.xively.com
    time=`/bin/date -u +%FT%XZ`
    if [ -n "$temp" ]; then
    /bin/echo "$time,$temp">>/home/pi/cosm/sensor/temperature/cosm.csv
    fi
    if [ -n "$rhum" ]; then
    /bin/echo "$time,$rhum">>/home/pi/cosm/sensor/humidity/cosm.csv
    fi
    if [ -n "$volt" ]; then
    /bin/echo "$time,$volt">>/home/pi/cosm/sensor/voltage/cosm.csv
    fi
    /bin/bash /home/pi/cosm/sensor/upload-cosm.sh > /dev/null 2>&1 &
    log=`/bin/date -u +%F@%X`
    log+=" | Values sent to xively.com"
    /bin/echo $log>>$log_file

    done < /dev/ttyAMA0

This is all that it processes:

    RHUM
    RHUM
    RHUM

If I take out the last block of code (to send the values to xively.com), it shows (which is what I need):

    RHUM
    TEMP
    RHUM
    TEMP
    RHUM
    TEMP

I've spent a lot of time trying to find out why doesn't the loop go through all the records and only processes the first one.

Can anyone shed a light or provide any working alternative?

Thanks in advance for any help.

2
  • Can you show the raw input? When you say "This is all that it processes" - do you mean that RHUM is the output? "it shows [...] what I need" - could you be specific about what you need? Commented Feb 14, 2016 at 0:55
  • RHUM is the output for the first line, as this is the result only ECHO I have in the program. TEMP is the output for the second line, so I would expect it to appear right after RHUM. Basically, I need it to process every 12 char as a line... Commented Feb 14, 2016 at 1:28

1 Answer 1

1

I edited the script for clarity, and ran it against input I made based on your first set of output. I don't think the loop skipped records - perhaps the input didn't match what you expected. The version below captures the raw data to a file, so you can verify the outcomes against the raw data.

#!/bin/bash

PATH=/bin:/usr/bin

log_file="/home/pi/logs/Temp_$(date +%Y%m%d).log"
log_file_raw=${log_file/./_raw.}

while read -r -n 12 dozen
do
    echo -n "$dozen" >> $log_file_raw

    date=`date -u +%F@%X`
    key=${dozen:3:4}
    val=${dozen:7}
    val=${val%-}

    case $key in
    TEMP)
        log="$date | Current Temperature: $val ºC"
        csv=/home/pi/cosm/sensor/temperature/cosm.csv
    ;;
    RHUM)
        log="$date | Current Relative Humidity: $val %"
        csv=/home/pi/cosm/sensor/humidity/cosm.csv
    ;;
    BATT)
        log="$date | Current Battery Voltage: $val V"
        csv=/home/pi/cosm/sensor/voltage/cosm.csv
    ;;
    *)
        continue
    ;;
    esac

    echo "$log" >> $log_file
    echo "${date/@/T}Z,$val" >> $csv

    /bin/bash /home/pi/cosm/sensor/upload-cosm.sh > /dev/null 2>&1 &
    echo "$date | Values sent to xively.com" >> $log_file

done < /dev/ttyAMA0

exit 0

One important change is that this script does not alter IFS. Each character of IFS is a separator. A good example of this is the LEEPING- for char5 when the input was (presumably) aSDSLEEPING-. Instead, this script uses the builtin bash substring feature of parameter expansion.

I left out the log rotation, because I want to suggest you log to syslog over the long term. The logger command will send a message to syslog. On most systems those logs are already rotated on a regular basis.

Sign up to request clarification or add additional context in comments.

5 Comments

Your suggestion worked perfectly: moving away from IFS to use the builtin bash substring feature of parameter expansion definitely did the trick. I have an additional question for you: considering that I never know the total number of char sent in every iteration (can be 24 - RHUM and TEMP or more - RHUM, TEMP, BATT), is there a way of identifying when I have reached the end of the string, to be able to know that my processing for that line is finished?
At a guess (I don't have one of these), if you did a single read with no size limit, it would consume all the characters available at that time. You could then use a for loop to operate on each dozen characters, for example while read -r buf; do for ((i=0; i<${#buf}; i+=12)); do echo ${buf:i:12}; done; done < /dev/ttyAMA0
Unfortunately running read -r on /dev/ttyAMA0 doesn't ever finish (from what I could understand from running script with bash -x), so your example yields no data. Any other idea?
Instead of read -r buf, how about buf=$(</dev/ttyAMA0)? (I usually use backticks, but can't seem to quote them properly here.)
OK, you could try buf=$(cat /dev/ttyAMA0)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.