Ben's notes

Linux, Unix, network, radio...

User Tools

Site Tools


serial_data_logger

Smart Meter - P1 data logger

This script will log serial data and prepend time/date stamp. The example below if P1 data from a smart meter. You can pipe this to rotatelogs to save the output to rotated logs.

  • Example output:
    # /usr/local/bin/serialWatch.exp ttyUSB0
    
    2014-06-16,21:25:44 Log starting...
    spawn [open ...]
    2014-06-16,21:25:45: 0
    2014-06-16,21:25:45: /XMX5XMXABCE000046867
    2014-06-16,21:25:45:
    2014-06-16,21:25:45: 0-0:96.1.1(31333430303738362020202020202020)
    2014-06-16,21:25:45: 1-0:1.8.1(05062.220*kWh)
    2014-06-16,21:25:45: 1-0:1.8.2(04235.032*kWh)
    2014-06-16,21:25:45: 1-0:2.8.1(00000.000*kWh)
    2014-06-16,21:25:45: 1-0:2.8.2(00000.000*kWh)
    2014-06-16,21:25:45: 0-0:96.14.0(0002)
    2014-06-16,21:25:45: 1-0:1.7.0(0000.75*kW)
    2014-06-16,21:25:45: 1-0:2.7.0(0000.00*kW)
    2014-06-16,21:25:45: 0-0:17.0.0(999*A)
    2014-06-16,21:25:45: 0-0:96.3.10(1)
    2014-06-16,21:25:45: 0-0:96.13.1()
    2014-06-16,21:25:45: 0-0:96.13.0()
    2014-06-16,21:25:45: 0-1:96.1.0(3238303131303038323335313030333132)
    2014-06-16,21:25:45: 0-1:24.1.0(03)
    2014-06-16,21:25:45: 0-1:24.3.0(140616210000)(08)(60)(1)(0-1:24.2.0)(m3)
    2014-06-16,21:25:45: (02418.609)
    2014-06-16,21:25:45: 0-1:24.4.0(1)
    2014-06-16,21:25:45: !
  • Log and timestamp script:
    #! /bin/sh
    # the next line restarts using expect \
    exec expect $0 ${1+"$@"}
    
    #!/usr/bin/expect -f
    #
    # serialWatch.exp
    #   Connect up to a device on a serial port
    #   Time stamp any incoming lines to stdout
    
           # port is any serial port (omit the /dev/ prefix)
           # e.g. ttya, cua0, serialA, serialB, boca01 - boca16
    
    if {$argc != 1} {
      puts "$argc, $argv"
      puts "usage: serial.exp port"
      exit
    }
    
    proc timeStamp {} {
      global tcl_version
      if {$tcl_version >= 7.5} {
        # "clock" command requires Tcl v7.5 or greater
        # internal routine a little faster than making a system call
        set stamp [clock format [clock seconds] -format %Y-%m-%d,%T]
      } else {
        # fall back to standard UNIX system call
        set stamp [exec /bin/date +%Y-%m-%d,%T]
      }
      return $stamp
    }
    
    puts "\n[timeStamp] Log starting..."
    set port /dev/$argv
    set spawned [spawn -open [open $port w+]]
    puts "[timeStamp]: [string trim $spawned \r\n]"
    set baud 9600
        # -parenb means don't use a parity bit
        # -cstopb means "not 2 stop bits, but 1"
        # cs8 means 8 bits
        # -echo means no echo (full duplex?)
    stty ispeed $baud ospeed $baud raw -echo cs7 parenb -parodd -cstopb onlcr < $port
    log_user 0
    
    # log each input line
    #  add a timeStamp at the beginning of each line
    while {1} {
      expect "\n" {
        puts "[timeStamp]: [string trim $expect_out(buffer) \r\n]"
      }
    }
  • Start logging after boot. Add to /etc/rc.local:
    echo "nohup /usr/local/bin/serialWatch.exp ttyUSB0 | rotatelogs -f /mnt/ram/p1data 86400 100M &" | at now+1min

rsync / init script

You can use the following script to sync the RAM disk to NAS. It wil also sync before shutdown. This has been tested on Raspbian (Raspberry PI) Debian.

  • Create script /etc/init.d/rsync-p1-data
    #!/bin/bash
    #
    # chkconfig: - 95 05
    
    ### BEGIN INIT INFO
    # Provides: rsync-p1-data
    # Required-Stop: $network $local_fs $remote_fs
    # Required-Start: $syslog
    # Default-Start: 2
    # Default-Stop: 0 1 6
    # Short-Description: sync RAM disk to NAS
    # Description: rsync network captures from RAM disk to NAS
    ### END INIT INFO
    
    prog=`basename $0`
    lockfile=/var/lock/$prog
    ramdisk=/mnt/ram
    nas=/mnt/pd-p1smartmeter
    
    stop() {
            [ "$EUID" != "0" ] && exit 4
            echo -n $"$prog, syncing RAM disk to NAS before shutdown."
            echo " ---- STOP runlevel: `/sbin/runlevel` date:  `date`" >> /var/log/rsync.log
            /usr/bin/rsync --quiet -a --log-file=/var/log/rsync.log $ramdisk/ $nas
            RETVAL=$?
            echo
            [ $RETVAL -eq 0 ] && rm -f $lockfile
            return $RETVAL
    }
    
    start() {
            [ "$EUID" != "0" ] && exit 4
            echo -n $"$prog, sync not needed at start-up."
            echo " ---- START runlevel: `/sbin/runlevel` date: `date`" >> /var/log/rsync.log
            RETVAL=$?
            echo
            [ $RETVAL -eq 0 ] && touch $lockfile
            return $RETVAL
    }
    
    sync() {
            [ "$EUID" != "0" ] && exit 4
            # Sync all files but last (the one open for writing) to nas dir and year/day subdirs.
            # remove source files from RAM disk, if sync was succesful.
    
            # first create directory structure
            mkdir -p $nas/`date +%Y/%m/%d`
          
            # sync files
            ls $ramdisk | sort -t. -k2 | head -n -1 | /usr/bin/rsync --quiet -a --remove-source-files --log-file=/var/log/rsync.log --files-from=- $ramdisk/ $nas/`date +%Y/%m/%d`
            RETVAL=$?
            return $RETVAL
    }
    
    # See how we were called.
    case "$1" in
      stop) 
            stop
            ;;
      start)
            start
            ;;
      sync) 
            sync
            ;;
    
      *)
            echo $"Usage: $0 {start|stop|sync}"
            exit 2
    esac
  • Enable script to run at stop/start
    update-rc.d rsync-p1-data defaults
    update-rc.d rsync-p1-data enable
  • Enable automatic sync every hour. Add to crontab:
    1 * * * * /etc/init.d/rsync-p1-data sync
serial_data_logger.txt · Last modified: 2021/10/09 15:14 by 127.0.0.1