Wednesday, September 13, 2017

Raspberry Pi detect keypress(es) and duration

Today I started my first Raspberry Pi project which involves HW (tactile switch). Setting up the required components on a proto board turned out to be less complex as expected, but when searching for python code to detect long/short keypress events (and eventually measure the time as well) I've not found nothing really useful. Thus I decided to accept the challenge and implement my own solution to distinguish between long an short key presses (via callback function) and to measure the time in ms.

import os
import RPi.GPIO as GPIO
import time

longpress_ctms=lambda: int(round(time.time()*1000))
longpress_cfg={}
longpress_event={}

def longpress_add(channel,bt,min,longcb,shortcb):
    global longpress_cfg

    longpress_cfg[channel]=dict({'bt':bt,'min':min,'lcb':longcb,'scb':shortch})
    GPIO.setup(channel,GPIO.IN,pull_up_down=GPIO.PUD_DOWN)
    GPIO.add_event_detect(channel,GPIO.BOTH,callback=longpress_cb,bouncetime=longpress_cfg[channel]['bt'])

def longpress_cb(channel):
    if GPIO.input(channel):
        longpress_press(channel)
    else:
        longpress_release(channel)
    
def longpress_press(channel):
    global longpress_event

    longpress_event[channel]=longpress_ctms()

def longpress_release(channel):
    global longpress_event
    
    dur=longpress_ctms()-longpress_event[channel]
    if dur>=longpress_cfg[channel]['min']:
        longpress_cfg[channel]['lcb'](channel,dur)
    else:
        longpress_cfg[channel]['scb'](channel,dur)

# Callbacks
def long(channel,duration):
    print 'Long press for channel '+str(channel)+' ('+str(duration)+'ms)'

def short(channel,duration):
    print 'Short press for channel '+str(channel)+' ('+str(duration)+'ms)'

# Init
GPIO.setmode(GPIO.BCM)
longpress_add(18,75,1000,long,short)
longpress_add(23,75,1000,long,short)

# Main loop
try:
    while True:
        time.sleep(1000)
except KeyboardInterrupt:
    pass
finally:
    GPIO.cleanup()


Parameters for "longpress_add" are:

channel - channel/pin to detect keypress for
bt - minimum time (bouncetime) between two callbacks in milliseconds
min - minimum duration for long presses
longcb - callback for long presses
shortcb - callback for short presses

Running the python script from above (for channel 18 + 23) I do get the following output:

$ python longpress.py
Short press for channel 18 (551ms)
Long press for channel 18 (2683ms)
Short press for channel 23 (312ms)
Long press for channel 23 (2081ms)
^C

I hope this post inspires you to create some fancy Raspberry Pi solutions as well and to share them with the community.

PS: This is one of my first python scripts ever, so please be gentle if there are some coding issues ...

Tuesday, June 20, 2017

ADB VV 2220 - Read statistics via bash

My beloved Pirelli PRGAV4202N modem died and I had to replace it with the (A1 branded) ADB VV2220 (v2/Firmware: E_9.4.1). In the past I've already created a couple of scripts to read current statistics, etc. but these are worthless now. Time for some hands-on!

So my first goal was to read the Diagnostic/Interfaces summary, but it turned out to be a little more complicated as expected, as the logon process requires some additional form fields (sha256 hash of the password, etc.) which are pre filled using javascript. In order to mimic this behaviour we first have to extract some values from the login page:


page=$(curl -v -k http://10.0.0.138/ui/login 2>&1)
nonce=$(echo "$page" | grep 'name="nonce"' | egrep -o 'value="(.*)"' | sed -n -E 's/value="(.*)"/\1/p')
code1=$(echo "$page" | grep 'name='\''code1'\''' | egrep -o 'value='\''(.*)'\''' | sed -n -E 's/value='\''(.*)'\''/\1/p')
code3=$(echo "$page" | grep 'name='\''code3'\''' | egrep -o 'value='\''(.*)'\''' | sed -n -E 's/value='\''(.*)'\''/\1/p')

Now I use the PHP function "hash_hmac" to create the sha256 hash (openssl could be used as well):

passwd=$(php -r "echo hash_hmac('sha256','Austria&Eur0
','$nonce');")

Using the hashed password we can now sign in and fetch the new session ID:

sid=$(curl -k -v -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "login=Login&userName=Telek0m&userPwd=$passwd&nonce=$nonce&code1=$code1&code3=$code3" http://$1/ui/login 2>&1 | grep "Set-Cookie:" | sed -n -E 's/.*Set-Cookie:.*sid=([^;]*).*/\1/p')

Using the session ID you have switch to enhanced mode first (seems to be requires as otherwise calling the diagnostics URI's ins't working), then fetch the "Diagnostic/Interfaces summary" and output it using html2text:

echo $(curl -k -v --header "Cookie: sid=$sid" "http://$1/ui/dboard?level=2")
echo "$(curl --header "Cookie: sid=$sid" "http://$1/ui/dboard/diagnostics/ifsummary?backto=diagnostics&p=1" 2>/dev/null | html2text -style pretty -o - )"

Voila here it is:

Interface summary
I've add the complete script (output is refreshed every 5s) below and A1 users in Austria can call it (others most likely have to adjust the command line parameters):


./adbstats.sh "10.0.0.138" "Telek0m" "Austria&Eur0"

I hope this post inspired you to create some fancy scripts as well (e.g. periodic reboot, etc.) and to share them with the community.

Cheers

adbstats.sh


#!/bin/bash
page=$(curl -v -k http://$1/ui/login 2>&1)
nonce=$(echo "$page" | grep 'name="nonce"' | egrep -o 'value="(.*)"' | sed -n -E 's/value="(.*)"/\1/p')
code1=$(echo "$page" | grep 'name='\''code1'\''' | egrep -o 'value='\''(.*)'\''' | sed -n -E 's/value='\''(.*)'\''/\1/p')
code3=$(echo "$page" | grep 'name='\''code3'\''' | egrep -o 'value='\''(.*)'\''' | sed -n -E 's/value='\''(.*)'\''/\1/p')
# Use php to create hash
passwd=$(php -r "echo hash_hmac('sha256','$3','$nonce');")
sid=$(curl -k -v -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "login=Login&userName=$2&userPwd=$passwd&nonce=$nonce&code1=$code1&code3=$code3" http://$1/ui/login 2>&1 | grep "Set-Cookie:" | sed -n -E 's/.*Set-Cookie:.*sid=([^;]*).*/\1/p')
# Switch to advanced mode
echo $(curl -k -v --header "Cookie: sid=$sid" "http://$1/ui/dboard?level=2")
while true
do
    clear
    echo "$(curl --header "Cookie: sid=$sid" "http://$1/ui/dboard/diagnostics/ifsummary?backto=diagnostics&p=1" 2>/dev/null | html2text -style pretty -o - )"
    Sleep 5
done