├── README.md └── disp_llb.sh /README.md: -------------------------------------------------------------------------------- 1 | # avakindle 2 | Remote public warning display based on amazon kindle DX with OS version 2.5.8 3 | 4 | For more information, visit: [snowtechblog.wordpress.com](http://snowtechblog.wordpress.com "What so ever") 5 | 6 | ## TODO'S 7 | #### TODO: Add serverside script 8 | #### TODO: list and explain futur improvements 9 | #### TODO: Links, code formatting 10 | #### TODO: Add start script, find it (on the kindle?) 11 | #### TODO: add more comments to source code 12 | 13 | ## Source description: 14 | 15 | The code is devided into three sections. The first block are function definitions. The second block are variables, initialize the WAN module and logfile, as well as defines that Kindle downloads the image on startup. The third block is the infinite while loop. OK, lets go through the third block to understand the logic ,-) 16 | 17 | **Note:** You must set your username `$MAIL_USER`, passwort `$MAIL_PW`, email address `$MAIL_ADD` and recipient mail address `$MAIL_RECIPIENT` to get the `send_log` working. 18 | 19 | #### Startup: 20 | 21 | Open a terminal on Kindle (you should know how to do this, otherwise (LINK MOBILEREAD) is your friend...). Start the code with redirecting all possible output, cause this will write over the fullscreen image: 22 | (FIND THE FILE ON KINDLE: START_LLB.SH or similar...) 23 | Before entering the loop, function `WAIT_FOR_SS` will cause a wait until state screensave is reached (remove USB cable! slide power button once to go to screensave manually). At the startup the variable `$DOWNLOAD_IMG` will be set to `YES`, but lets neglect that for the moment, so its value is `NO`. So the code jumps into the function `WAIT_FOR_READY`. 24 | 25 | #### WAIT_FOR_READY: 26 | 27 | This is acually the heart of the loop, its doing much more than just wait. It waits until the state "Ready to suspend" and then calls the function to calculate the next wakeup (`calc_wakeup`) and to write the wakeup value to the RTC (`write_wakeup`). 28 | The trick with the `$AWAKE_AGAIN` variable is to ensure that the function to calculate and to write the wakeup time is only called once and not multiple times (remember the state "ready to suspend" is 5 seconds long and I experienced that writing the wakeup time to often to the RTC can cause a failure and Kindle is in gone to never ending sleep). So always when Kindle is in a state where grep does not find anything with "Ready" (all other states), the `$AWAKE_AGAIN` is set to `YES` and as soon as entering "Ready" there are 5 seconds to perform `calc_wakeup` and `write_wakeup`. 29 | 30 | #### CALC_WAKEUP: 31 | 32 | This checks the actions and calculates the next wakeup. There are three possibilities. 1st: The last download try failed (file not found on server, not connection etc.) and `$DL_FAILED` is `YES`, so Kindle will try in `$WAKEUP_CHECK_DEFAULT_FAIL` (def=600) seconds again. If `$DL_FAILED` is `NO`, we calculate the `$DIFF_TIME` which is the time between next action and the current time. If the `$DIFF_TIME` is larger than the `$WAKEUP_CHECK_DEFAULT` (def=3600) seconds, Kindle will wake up again in this time. If `$DIFF_TIME` is smaller, Kindle needs to consider to sleep again or to start the download. Note 1: the Kindle never wakes up excatly on time, so there is a time window (`$STAY_AWAKE` def=240sec) when to consider an action to be ready to download. Note 2: Better never try to sleep for less than 60 seconds (or 120 seconds?), remember that the wakeup process takes at least a minute in screensaver state. 33 | 34 | In any case, the output of `$CALC_WAKEUP` will be a new value for the variable to trigger the download `$DOWNLOAD_IMG` and the next wakeup time `$WAKE_TIME`. The `$WAKE_TIME` will be used in `write_wakeup`: 35 | 36 | #### WRITE_WAKEUP: 37 | 38 | Write the wakeup time to the RTC. First checks that `$WAKE_TIME` contains a reasonable value, that is `$WAKE_TIME` larger than `$WAKEUP_MINIMAL` (def=60sec) and that we have enough time to set the wakeup, that is `$TIME_LEFT` in "Ready for Suspend" is larger than `$LATEST_WAKEUP_SET` (def=0sec, we have to risk everything to try to write the wakeup ...). If Kindle should download the image (this is done in Active state), we dont want to write a wakeup (could be in conflict with switching the state) but bring the kindle into active (NOTE: this should not be done by `powerd_test -p` without any state checking, cause this can make a lot of trouble... definitely a point to improve!). 39 | 40 | OK, now Kindle wakes up `$WAKEUP_CHECK_DEFAULT` (every hour) and on specific times defined in `$ACTION` (space separated string of time, in my case two actions per day always at 08:15 and 17:15). Now, when an Action is active, variable `$DOWNLOAD_IMG` is set to `YES` and the conditional in the infinite loop is entered. Remember that we enter in Screensave mode (hopefully), so `wait_for_ss` will not delay. Then, we switch into active to have 10minute to perform all the stuff we want Kindle to do in the action. In my case its defined in `DOWNLOAD_LLB`. 41 | 42 | #### DOWNLOAD_LLB: 43 | 44 | Turns WAN on, checks for connection, download image, sync the time and sends the logfile via email. If its not possible to get connection, `set_retries` is called to count the number of retries. To prevent from checking infinitely long every ten minutes for a download, the retries are limited to the number `$DL_RETRIES` (def=3). This results in `$DL_FAILED=YES` for the next run of `calc_wakeup`. If Kindle is able to connect, the task mentioned are performed. For the download server set the variable $IMG_URL to your needs. Note that Kindles version of wget does not support to check for a never file. This would be a nice-to-have. So a second improvement goes into that direction ... 45 | 46 | 47 | #### SEND_LOG: 48 | `send_log` need some special notes. Kindle does not give a mail agent, so I use sendmail from a recent busybox compilation. I found that a precompiled ARM7L version works on kindle (LINK???). You need to specify the path to it in the function. And you need to setup the sendmail command to work with your provide, e.g. set the variables `$MAIL_USER`, `$MAIL_PW`, `$MAIL_ADD` and `$MAIL_RECIPIENT` to your values. 49 | 50 | #### DISPLAY_IMAGE: 51 | 52 | Last and least, we need to display the downloaded image with `display_image`. This is done with Kindles internal command `eips`. Since my project should work in the cold, Kindle runs `eips` several times in hope that the eInk display gets better contrast by writing the pixels several times. 53 | -------------------------------------------------------------------------------- /disp_llb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ########################### 4 | # TODO: write a state check function! using powerd_test -p without state 5 | # is a bad idea! 6 | ########################### 7 | 8 | ########################### 9 | # TODO: read mail user from external file, add this file to .gitignore 10 | ########################### 11 | 12 | ########################### 13 | # TODO: make image showing that we try to refresh 14 | ########################### 15 | 16 | # ------------------------------- 17 | # START: FIRST BLOCK: FUNCTIONS 18 | 19 | send_log () { 20 | /mnt/us/busybox_test/busybox-armv7l sendmail -H "exec openssl s_client -quiet -connect mail.gmx.net:25 -tls1 -starttls smtp" -f "$MAIL_ADD" -au"$MAIL_USER" -ap"$MAIL_PW" $MAIL_RECIPIENT -v < $LOG_FILE 21 | if [ $? ]; then 22 | echo $mail_first_line > $LOG_FILE 23 | msg "Log file send! emptied log!" 24 | else 25 | msg "could not send log file ..." 26 | fi 27 | } 28 | 29 | wait_for_ss () { 30 | PSTATE=`powerd_test -s | grep Screen` 31 | while [ "$PSTATE" = "" ]; do 32 | sleep 1 33 | PSTATE=`powerd_test -s | grep Screen` 34 | msg "wait for Screen Saver!" 35 | done 36 | } 37 | 38 | wait_for_ready () { 39 | # wait until Ready for Suspend 40 | #msg "wait_for_ready: `powerd_test -s | grep Remaining | awk '{print $6}'` s left in '`powerd_test -s | grep Power | awk '{print $3 $4}'`'" 41 | PSTATE=`powerd_test -s | grep Ready` 42 | # Only first call after Suspend/screensaver should enter the loop 43 | while [ "$PSTATE" = "" ]; do 44 | sleep 1 45 | PSTATE=`powerd_test -s | grep Ready` 46 | AWAKE_AGAIN="YES" 47 | done 48 | # if that was the first call, we write the default wakeup to always wake up again. 49 | if [ "$AWAKE_AGAIN" = "YES" ]; then 50 | # We are awake again! Check only once the ACTIONS 51 | msg "------------------------------------------" 52 | msg "Recalculate and set next wakeup or action!" 53 | DOWNLOAD_IMG="YES" 54 | 55 | # output: WAKE_TIME and DOWLOAD_IMG 56 | calc_wakeup 57 | 58 | WAKEUP_S=$WAKE_TIME 59 | write_wakeup 60 | AWAKE_AGAIN="NO" 61 | fi 62 | } 63 | 64 | msg () { 65 | #if [ "$2" == "" ]; then 66 | # echo "`date`: $1" 67 | # else 68 | echo "`date`: $1" >> $LOG_FILE 69 | #fi 70 | } 71 | 72 | # this function returns WAKE_TIME and set DOWNLOAD_IMG 73 | calc_wakeup () { 74 | # CHECK TIME, and recalc sleep timer 75 | CURRENT_TIME=`date +%s` 76 | # Winterzeit 77 | CURRENT_TIME=`expr $CURRENT_TIME + 3600` 78 | # daily basis 79 | D_TIME=`expr $CURRENT_TIME % "86400"` 80 | # initialize WAKE_TIME_set (internal of output WAKE_TIME) 81 | WAKE_TIME_set=$WAKEUP_CHECK_DEFAULT 82 | 83 | if [ "$DL_FAILED" == "YES" ]; then 84 | # We could not load image last time - FAIL mode 85 | msg_str_d="Fail Mode, retry in $WAKEUP_CHECK_DEFAULT_FAIL s." 86 | CURR_ACTION="Fail mode" 87 | WAKE_TIME_set=$WAKEUP_CHECK_DEFAULT_FAIL 88 | #DL_FAILED="NO" 89 | DEFER_STAY_AWAKE="NO" 90 | # SHOULD HERE DONWLLOAUD _IMG set to YES ????? 91 | else 92 | # see if there is an action coming close, if so, manipulate WAKE_TIME_set 93 | 94 | # get closest action 95 | WAKE_TIME_set=$WAKEUP_CHECK_DEFAULT 96 | CURR_ACTION="Default wakeup" 97 | for ACTION in `echo $ACTION_TIME | awk '{ s = ""; for (i = 1; i <= NF; i++) print $i }'`; do 98 | # convert hh:ss into seconds since 00:00 99 | DESIRED=`echo $ACTION | sed 's/:/ /g' | awk '{print ($1*3600)+($2*60)}'` 100 | DIFF_TIME_V=`expr $DESIRED - $D_TIME`; 101 | # get absolut value of DIFF_TIME 102 | #DIFF_TIME=`echo ${DIFF_TIME_V#-}` 103 | # negative if past, positive in secons to the event... 104 | #DIFF_TIME=`expr $DIFF_TIME_V \* -1`; 105 | DIFF_TIME=$DIFF_TIME_V 106 | 107 | if [ $DIFF_TIME -lt $WAKE_TIME_set ]; then 108 | if [ $DIFF_TIME -ge 120 ]; then 109 | # we remove some time, to not wake up to late. 110 | WAKE_TIME_set=`expr $DIFF_TIME - 120` 111 | CURR_ACTION=$ACTION 112 | elif [ $DIFF_TIME -gt -120 ] && [ $DIFF_TIME -lt 120 ]; then 113 | # ok, download! 114 | WAKE_TIME_set=0 115 | CURR_ACTION=$ACTION 116 | else 117 | # action past 118 | msg "$ACTION: $DIFF_TIME s since the action - sleep again!" 119 | fi 120 | else 121 | msg "$ACTION: $DIFF_TIME is larger than $WAKE_TIME_set - sleep again!" 122 | fi 123 | done 124 | # charaterize action 125 | if [ $WAKE_TIME_set -lt $WAKEUP_CHECK_DEFAULT ]; then 126 | # We are really close to the event, trigger download. 127 | if [ $WAKE_TIME_set -lt $STAY_AWAKE ] && [ "$DEFER_STAY_AWAKE" == "NO" ]; then 128 | DOWNLOAD_IMG="YES" 129 | msg_str_d="only $WAKE_TIME_set s away from ' $CURR_ACTION ' action, trigger Download." 130 | DEFER_STAY_AWAKE="YES" 131 | # We are close, but its worse going into sleep again 132 | else 133 | msg_str_d="$WAKE_TIME_set s from ' $CURR_ACTION ' away, will sleep again" 134 | DOWNLOAD_IMG="NO" 135 | DEFER_STAY_AWAKE="NO" 136 | fi 137 | # We are hours away, we will sleep for WAKEUP_CHECK_DEFAULT 138 | else 139 | msg_str_d="More than $WAKEUP_CHECK_DEFAULT s from next action away, will sleep again" 140 | DOWNLOAD_IMG="NO" 141 | DEFER_STAY_AWAKE="NO" 142 | fi 143 | fi 144 | msg "$msg_str_d" 145 | msg "Next ACTION='$CURR_ACTION', will Suspend for $WAKE_TIME_set s ..." 146 | WAKE_TIME=$WAKE_TIME_set 147 | } 148 | 149 | download_llb () { 150 | # turn on WAN 151 | msg "turn WAN ON: `powerd_test -s | grep Remaining | awk '{print $6}'` s in '`powerd_test -s | grep Power | awk '{print $3 $4}'`'" 152 | lipc-set-prop com.lab126.wan startWan 1 153 | 154 | # wait befor continue evaluating the connection 155 | sleep $PRE_SLEEP 156 | 157 | TIMER=${NETWORK_TIMEOUT} # number of seconds to attempt a connection 158 | CONNECTED=0 # whether we are currently connected 159 | while [ 0 -eq $CONNECTED ]; do 160 | # test whether we can ping outside 161 | ifconfig | grep ppp0 && CONNECTED=1 162 | #/bin/ping -c 1 -I ppp0 $TEST_DOMAIN && CONNECTED=1 163 | 164 | # if we can't, checkout timeout or s leep for 1s 165 | if [ 0 -eq $CONNECTED ]; then 166 | TIMER=$(($TIMER-1)) 167 | if [ 0 -eq $TIMER ]; then 168 | msg "No internet connection after ${NETWORK_TIMEOUT} seconds, aborting." 169 | break 170 | else 171 | sleep 1 172 | fi 173 | fi 174 | done 175 | 176 | sleep $PRE_SLEEP 177 | 178 | # download 179 | if [ 1 -eq $CONNECTED ]; then 180 | msg "WAN connected, start download ..." 181 | dnow=`date '+%Y-%m-%d-%H-%M-%S'` 182 | 183 | if [ -f FN_TEMP ]; then 184 | rm $FN_TEMP 185 | fi 186 | wget -O $FN_TEMP $IMG_URL 187 | if [ $? ]; then 188 | # Sucess 189 | msg "Download image successfull" 190 | if [ -f FN ]; then 191 | rm $FN 192 | fi 193 | # rename temporary image to recent bulletin 194 | mv $FN_TEMP $FN 195 | DEFER_STAY_AWAKE="YES" 196 | DL_FAILED="NO" 197 | RETRIES=0 198 | else 199 | # Failed 200 | msg "Could not download recent image, trigger fail_mode" 201 | DL_FAILED="YES" 202 | set_retries 203 | fi 204 | DOWNLOAD_IMG="NO" 205 | 206 | # sync the time 207 | ntpdate $NTP_SERVER 208 | if [ $? -ne 0 ]; then 209 | msg "Could not receive current time!" 210 | else 211 | msg "Time sync successfull" 212 | hwclock -w 213 | fi 214 | 215 | # send log 216 | send_log 217 | else 218 | msg "Failed to connect, trigger fail_mode" 219 | DL_FAILED="YES" 220 | set_retries 221 | fi 222 | # Stop WAN 223 | lipc-set-prop com.lab126.wan stopWan 1 224 | CONNECTED=0 225 | 226 | msg "WAN OFF: `powerd_test -s | grep Remaining | awk '{print $6}'` s in '`powerd_test -s | grep Power | awk '{print $3 $4}'`'" # >> /mnt/us/llb/wakeup.log 227 | } 228 | 229 | set_retries () { 230 | if [ $RETRIES -gt $DL_RETRIES ]; then 231 | msg "$RETRIES times failed to download llb. Switch to normal wake up intervals!" 232 | DOWNLOAD_IMG="YES" 233 | DL_FAILED="NO" 234 | DEFER_STAY_AWAKE="NO" 235 | RETRIES=0 236 | fi 237 | RETRIES=`expr $RETRIES + 1` 238 | } 239 | 240 | write_wakeup () { 241 | # look if smaller WAKEUP_MINIMAL or even negative waketime, 242 | # and if so set to WAKEUP_MINIMAL 243 | if [ $WAKEUP_S -lt $WAKEUP_MINIMAL ]; then 244 | msg "Desired wakeup in '$WAKEUP_S' smaller than 'WAKEUP_MINIMAL', reset to $WAKEUP_MINIMAL" 245 | WAKEUP_S=$WAKEUP_MINIMAL 246 | fi 247 | TIME_LEFT=`powerd_test -s | grep Remaining | awk '{print int($6)}'` 248 | # go to sleep. 249 | if [ $DEFER_STAY_AWAKE == "NO" ]; then 250 | # make sure that we have enough time to process 'write_wakeup' 251 | if [ $TIME_LEFT -gt $LATEST_WAKEUP_SET ]; then 252 | lipc-set-prop -i com.lab126.powerd rtcWakeup $WAKEUP_S 253 | SUCESS_SET_WAKEUP=$? 254 | #echo 1 > /sys/class/rtc/rtc0/device/wakeup_enable 255 | if [ $SUCESS_SET_WAKEUP -eq 0 ]; then 256 | msg "set rtcWakeup to $WAKEUP_S" # >> /mnt/us/llb/wakeup.log 257 | #eips 0 0 "`date`: Wakeup in $WAKEUP_S second" 258 | else 259 | msg "Huch? Could not set wake up to '$WAKEUP_S'. Error '$SUCESS_SET_WAKEUP'" 260 | fi 261 | else 262 | msg "We are to late, to set wakeup ..." 263 | fi 264 | # next round is download, stay awake! 265 | else 266 | DOWNLOAD_IMG="YES" 267 | # we are in ready to suspend, hit it once to get to active 268 | powerd_test -p 269 | msg "Oh, we will download soon !" 270 | display_refresh 271 | sleep 10 272 | # hit a second time to go screensaver 273 | powerd_test -p 274 | display_refresh 275 | fi 276 | } 277 | 278 | display_image () { 279 | # display most recent image 280 | msg "Display image!" 281 | eips -c 282 | sleep 1 283 | eips -f -g $1 284 | #eips -c 285 | sleep 1 286 | eips -f -g $1 287 | #eips -c 288 | sleep 1 289 | eips -f -g $1 290 | #eips -c 291 | sleep 1 292 | eips -f -g $1 293 | #eips -c 294 | sleep 1 295 | eips -f -g $1 296 | } 297 | 298 | display_refresh () { 299 | msg "Display refresh message!" 300 | eips -c 301 | eips 10 32 "Download most recent Bulletin ... Please wait ..." 302 | } 303 | # END: FIRST BLOCK: FUNCTIONS 304 | # ------------------------------- 305 | 306 | 307 | 308 | # ------------------------------- 309 | # START: SECOND BLOCK: VARIABELS 310 | 311 | # Define ACTIONs 312 | ACTION_TIME="08:15 17:15" 313 | 314 | # dont sleep 4 min before action 315 | STAY_AWAKE="240" 316 | # wake and check time every hour 317 | WAKEUP_CHECK_DEFAULT=3600 318 | # if fail, retry to DL every 10 min 319 | WAKEUP_CHECK_DEFAULT_FAIL=600 320 | # retries after failure, before switch to normal WAKEUP_CHECK_DEFAULT 321 | DL_RETRIES=3 322 | # Minimal sleep time in seconds 323 | WAKEUP_MINIMAL=60 324 | # rtcWakeup should not be set less than X second before sleep 325 | LATEST_WAKEUP_SET=0 326 | 327 | # WAN 328 | NETWORK_TIMEOUT=60 329 | TEST_DOMAIN="195.186.152.33" 330 | # time to wait after switching WAN on 331 | #+wait this time again, after detecting WAN connecting 332 | PRE_SLEEP=20; 333 | NTP_SERVER="1.ch.pool.ntp.org" 334 | IMG_URL="http://www.url.to/your/image.png" 335 | 336 | mail_first_line="Subject:Log-file avalanche Kindle" 337 | MAIL_USER="your_mail_provider_username" 338 | MAIL_PW="your_mail_provide_password" 339 | MAIL_RECIPIENT="your_mail_to_receive_log@provide.ch" 340 | MAIL_ADD="your_kindle_mail_account@gmx.ch" 341 | 342 | # image file and folder 343 | FOLDER="/mnt/us/cron_script/recent" 344 | FN_TEMP=$FOLDER/llb_temp.png 345 | FN=$FOLDER/llb.png 346 | 347 | LOG_FILE="/mnt/us/cron_script/disp_llb.log" 348 | 349 | 350 | # initialize empty Log-File 351 | if [ -f "$LOG_FILE" ]; then 352 | rm $LOG_FILE 353 | fi 354 | touch $LOG_FILE 355 | # add subject. 356 | echo $mail_first_line > $LOG_FILE 357 | 358 | # initialize the WAN device 359 | wan_dev=1 360 | while [ $wan_dev -eq 1 ]; do 361 | wancontrol wanon 362 | wan_dev=$? 363 | if [ $wan_dev -eq 1 ]; then 364 | msg "wancontrol wanon: failed, check in 20s again" 365 | sleep 10 366 | wancontrol wanoff 367 | sleep 10 368 | fi 369 | done 370 | 371 | # Set internal start values: 372 | # load the image in first round 373 | DOWNLOAD_IMG="YES" 374 | # we do not wake up accurately on time, do the action in a timespan 375 | DEFER_STAY_AWAKE="NO" 376 | WAKEUP_S=$WAKEUP_CHECK_DEFAULT 377 | RETRIES=1 378 | DL_FAILED="NO" 379 | NO_WAKEUP_DEAMON=0 380 | 381 | # END: SECOND BLOCK: VARIABELS 382 | # ------------------------------- 383 | # 384 | ################################# 385 | # 386 | # ------------------------------- 387 | # START: THIRD BLOCK: INFINITE LOOP 388 | 389 | 390 | # initial wait until user pressed power button to start the main loop 391 | wait_for_ss 392 | 393 | # Start never ending loop... 394 | # ------------------------------- 395 | while [ 1 -eq 1 ]; do 396 | # DOWNLOAD_IMG 397 | if [ "$DOWNLOAD_IMG" = "YES" ]; then 398 | # Download will be performed in 'active'-mode: 399 | # we need to wait for screen save: never simulate the power 400 | #+button in 'active' and bring the kindle into never ending sleep 401 | wait_for_ss 402 | # turn into active: 403 | powerd_test -p 404 | # display refresh screen 405 | display_refresh 406 | #returns DL_FAILED="NO" if succesfull download 407 | download_llb 408 | # switch back to screensave 409 | powerd_test -p 410 | # display most recent image, or if failed display the last image... 411 | display_image $FN 412 | fi 413 | 414 | # SET WAKE UP 415 | # this wait statement does check if we need to sleep again, 416 | #+AND recalc the wakeup time and set the rtcWakeup as well 417 | wait_for_ready 418 | sleep 2 419 | msg "Mainloop: `powerd_test -s | grep Remaining | awk '{print $6}'` s in '`powerd_test -s | grep Power | awk '{print $3 $4}'`'" 420 | done 421 | 422 | # END: THIRD BLOCK: INFINITE LOOP 423 | # ------------------------------- 424 | --------------------------------------------------------------------------------