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

Tuesday, September 27, 2011

Cisco VPN Client - Auto-connect & remember password

My ISP disconnects the DSL line every 8 hours (+new public IP) and thus my company VPN connection is disconnected as well. As this is very annoying I configured my VPN Client (Windows, 5.0.07.0410) to automatically connect and to remember my password.

To enable auto-connect (Automatic VPN Initiation) edit the file vpnclient.ini (for my case this file is located in folder "C:\Program Files\Cisco Systems\VPN Client") and add the following lines:

...
AutoInitiationEnable=1
AutoInitiationRetryInterval=15
AutoInitiationRetryIntervalType=1
AutoInitiationList=aconn
EnableLog=0
[aconn]
ConnectionEntry=MyCompany
Connect=1
...


The param "AutoInitiationRetryInterval" is used to set the reconnect interval (in minutes or seconds) depending on "AutoInitiationRetryIntervalType" where 0=minutes and 1=seconds.
I created a new ini section named "aconn" for my connection entry "MyCompany" (points to a connection profile named "MyCompany.pcf"), here you simply replace "MyCompany" with the name of your connection entry (fyi, you can add multiple ini sections comma separated to param "AutoInitiationList").

Regarding remembering the password the admin can override your settings in the remote profile (which happend in my case), so I had to do a little trick here. Exit the VPN client and open the respective local profile file (for my case the profile files are located in folder "C:\Program Files\Cisco Systems\VPN Client\Profiles") and add the following lines:

...
SaveUserPassword=1
UserPassword=mySecret
enc_UserPassword=

...

Set param "UserPassword" to your actual password, safe the file and make the profile file READ ONLY, because whenever you connect successfully the remote profile settings will override some of your local settings!
NOTE: Please do not forget to remove the read only flag whenever you want to edit the profile.

Now the VPN client should now automatically (re)connect. I know that this mini HowTo is not the sorcerer's stone, but I hope it saves you from waste of time for googling around and trial&error.

br
≠ logic

References:
http://www.cisco.com/en/US/docs/security/vpn_client/cisco_vpn_client/vpn_client46/administration/guide/vcAch4.html

Wednesday, September 21, 2011

FreeFileSync - Wake On LAN for NAS (Buffalo LinkStation™ Duo)

Last week after my hard-disk crashed and I realized that my backups are outdated, I decided to do it right this time. So I purchased a Buffalo Link Station Duo (2TB,Raid1, good price-performance ratio) as backup device and was absolutely convinced that with a few clicks I could easily setup a pure Windows based backup scenario.
But first of all my Windows7 Home Premium doesn't support SyncCenter and the second issue is that I was not happy with the "NAS PM Service", which caused the NAS station to start-up when ever I turned on my PC. This almost jeopardized my initial idea, because all I wanted to achieve was to activate the NAS, run the backup and finally shutdown the NAS until the next time the scheduler runs.
Time for some hands-on!

So here is my solution which works without the Buffalo NASNavi Suite and may work for other vendors/products as well:

In combination with the utility WolCmd.exe I created 2 additional scripts (WOL.bat,WOL.svn) which I use to wake-up and/or keep-alive the NAS. Simply download WolCmd.exe, create WOL.bat, WOL.svn (find source code below) and copy the files to (for now the directory is hard coded) C:\Program Files\Utils. Once this is done you can use WOL.bat for ...

Linkstation wakeup
"C:\Program Files\Utils\WOL.bat" wol [MAC] [IP] [NetMask] [Port] [Runs] [Interval in seconds]
Example:
"C:\Program Files\Utils\WOL.bat" wol 4ce6XXXXXXXX 10.0.0.XX 255.255.255.0 9 5 45

Start Linkstation keepalive
"C:\Program Files\Utils\WOL.bat" start [jobID] [IP] [NetMask] [Port] [Interval in seconds]
Example:
"C:\Program Files\Utils\WOL.bat" start backup 4ce6XXXXXXXX 10.0.0.XX 255.255.255.0 9 5

Stop Linkstation keepalive
"C:\Program Files\Utils\WOL.bat" end [jobID]
Example:
"C:\Program Files\Utils\WOL.bat" end backup

Using the Windows Task Scheduler and FreeFileSync I now run a daily backup and the Linkstation is only active while FreeFileSync runs (+ a couple of minutes until it shuts down). The image below shall give you an idea how to use WOL.bat to wake-up (duration 5*45s) and keep-alive (5s interval) your Linkstation while your e.g. backup executes.



I hope this information is useful for you, helps to conserve energy and please apologize if there are typo(s), grammar error(s), etc. because my native language is German (and this is my first blog entry).

br
≠ logic
  • Software
FreeFileSync http://sourceforge.net/projects/freefilesync/
WolCmd.exe - http://www.depicus.com/wake-on-lan/wake-on-lan-cmd.aspx
  • Scripts
WOL.bat

@ECHO OFF

IF /I "%1"=="__myself" (

    FOR /L %%l IN (0,0,0) DO (

        :: WOL command example -- "C:\Program Files\Utils\WolCmd.exe" 4ce67696094b 10.0.0.62 255.255.255.0 9
        "C:\Program Files\Utils\WolCmd.exe" %3 %4 %5 %6

        :: Delay for n (>1) seconds
        ping -n %7 127.0.0.1 > nul
    )

) ELSE (

    SET prefix=w0L_-
    SET postfix=-_L0w

    IF /I "%1"=="start" (

        :: ECHO %0 __myself %prefix%%2%postfix% %3 %4 %5 %6 %7
        START "%2" /I /MIN cmd.exe /C %0 __myself %prefix%%2%postfix% %3 %4 %5 %6 %7

    ) ELSE (

        IF /I "%1"=="end" (

            START "Kill: %2" /I cmd.exe /C cscript "%~dp0WOL.vbs" %prefix%%2%postfix%

        ) ELSE (

            IF /I "%1"=="wol" (

                FOR /L %%l IN (%6,-1,1) DO (

                    :: WOL command example -- "C:\Program Files\Utils\WolCmd.exe" 4ce67696094b 10.0.0.62 255.255.255.0 9
                    "C:\Program Files\Utils\WolCmd.exe" %2 %3 %4 %5

                    :: Delay for n (>1) seconds
                    ping -n %7 127.0.0.1 > nul
                )
            )
        )
    )
)


WOL.vbs

Set oShell = CreateObject("WScript.Shell")

if WScript.Arguments.Count >= 1 then

    Dim objWMIService
    Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & "." & "\root\cimv2")
    Dim colProcess
    Set colProcess = objWMIService.ExecQuery ("Select * from Win32_Process Where Name = 'cmd.exe'")

    For Each objProcess in colProcess

        Dim re1,re2
        Set re1 = new RegExp
        Set re2 = new RegExp

        re1.Pattern = ".*[ ]{1}__myself[ ]{1}.*"
        re2.Pattern = ".*[ ]{1}" & WScript.Arguments(0) & "[ ]{1}.*"

        Dim m1,m2
        Set m1 = re1.Execute(objProcess.CommandLine)
        Set m2 = re2.Execute(objProcess.CommandLine)

        WSCript.Echo m1.Count & "|" & re1.Pattern & "|" & objProcess.CommandLine
        WSCript.Echo m2.Count & "|" & re2.Pattern & "|" & objProcess.CommandLine

        if m1.Count > 0 AND m2.Count > 0 then

            WSCript.Echo objProcess.CommandLine

            objProcess.Terminate()
            WScript.Quit()

        end if

    Next

end if