Cordova Plugin config-file Element

In the [Cordova Plugin Reference], under `config-file Element`, the text reads “The config-file element only allows you to append new children to an XML document tree”. The Cordova NPM module installs globally into the following:

%USERPROFILE%\AppData\Roaming\npm\node_modules\cordova

It would be great to make existing `XML` content editable. The plugin code has logic to remove elements, but it hasn’t been exposed or documented.

Raspberry PI Security Camera

To setup a Raspberry PI security camera.

I flash the SD with the latest [NOOBS] after formatting the SD card with the [SDCard Formatter].

Boot into the desktop and put the Raspberry PI on the wifi network.

Enable the [camera interface] and reboot.

Sudo edit the /boot/config.txt file. Disable the camera LED by adding the entry:

disable_camera_led=1

Install the [poster] module by running the command-line:

sudo pip install poster

Create the file: ~/superscript

cd ~/Documents/PythonScripts/Camera/
python capture_image.py

Add execute permissions to superscript.

chmod +x ~/superscript

Create a folder for the Camera Python scripts.

mkdir ~/Documents/PythonScripts
mkdir ~/Documents/PythonScripts/Camera/

Create the ~/Documents/PythonScripts/Camera/capture_image.py script. Rotate the camera as necessary.

#get access to the camera
from picamera import PiCamera

#import so we can invoke another script
import subprocess

#get access to the clock
import datetime

# get access to sunrise and sunset
from astral import Location

#sleep so we can wait on the camera
from time import sleep

from fractions import Fraction

# create a camera object
camera = PiCamera()

#set the image resolution
camera.resolution = (640, 480)

#rotate the camera if upside-down
camera.rotation = 180

#flip the camera on the horizontal
camera.hflip = True

i = 0;

#record defaults
framerate = camera.framerate
shutter_speed = camera.shutter_speed
exposure_mode = camera.exposure_mode
iso = camera.iso

while True:

  # Get sunrise and sunset for Monroe, WA
  l = Location()
  l.latitude = 47.887059
  l.longitude = -121.8792998
  l.timezone = 'US/Pacific'

  sunrise = l.sun()['dawn']
  sunriseHour = int(sunrise.strftime('%H'))
  sunriseMinute = int(sunrise.strftime('%M'))
  sunset = l.sun()['sunset']
  sunsetHour = int(sunset.strftime('%H'))
  sunsetMinute = int(sunset.strftime('%M'))

  hours = int(datetime.datetime.now().strftime('%H'))
  minutes = int(datetime.datetime.now().strftime('%M'))
  seconds = int(datetime.datetime.now().strftime('%S'))

  if (hours >= sunriseHour and hours <= sunsetHour):
    #print 'work in the light'
    camera.framerate = framerate
    camera.shutter_speed = shutter_speed
    camera.exposure_mode = exposure_mode
    camera.iso = iso
  else:
    #print 'work in the dark'
    camera.framerate = Fraction(1,6)
    camera.shutter_speed = 6000000
    camera.exposure_mode = 'off'
    camera.iso = 800

  #show preview with some transparency
  #camera.start_preview(alpha=200)

  #wait two seconds for camera lighting
  #sleep(2)

  filename = 'image'+str(i)+'.jpg'

  #save image locally
  camera.capture(filename)

  #invoke the script to upload the image
  subprocess.call('python save_image.py '+filename, shell=True)

  #stop the preview
  #camera.stop_preview()

  sleep(3)

  i = (i + 1) % 12

Create the save_image.py script. Alter the domain and path to ~/Documents/PythonScripts/Camera/save_image.py.

#!/usr/bin/env python

import urllib, urllib2, os, os.path, sys
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers

command = os.popen('ifconfig | grep -A1 wlan0')
client_ip = command.read()
#print client_ip

register_openers()

if (len(sys.argv) > 1):
  filename = sys.argv[1];
else:
  filename = 'image.jpg';

query = { 'filename' : filename, 'client_ip' : client_ip }
url = "http://domain/path/save_image.php?"+urllib.urlencode(query)

print 'Saved: '+filename;
if (os.path.isfile(filename)) :
  values = {'image':open(filename)}
  data, headers = multipart_encode(values)
  headers['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
  headers['filename'] = filename
  req = urllib2.Request(url, data, headers)
  req.unverifiable = True
  content = urllib2.urlopen(req).read()
  #print (content)
else:
  print 'No image file found to upload\r\n';

On your PHP server somewhere, make a new folder and create the page save_image.php.

<?php

$filename = "image.jpg";
if ($_GET['filename'] != null) {
   $filename = $_GET['filename'];
}

if ($_GET['client_ip'] != null) {
   $clientip = $_GET['client_ip'];
   file_put_contents('client_ip.txt', $clientip);
}

$image = $_FILES["image"];

if ($image == null) {
   echo "Missing image to save as: ";
   echo $filename;
} else {
   echo "Saved image!";
   $tmp_name = $_FILES["image"]["tmp_name"];
   move_uploaded_file($tmp_name, $filename);
}

?>

On your PHP server somewhere, save the page images.php near your server image paths.

<html>
<?php
function displayFirstImage($path) {
   $files = glob($path);
   usort($files, function($a, $b) {
      return filemtime($a) < filemtime($b);
   });
   foreach($files as $file){
      printf('<img src="%1$s"/>', $file);
      break;
   }
}
displayFirstImage('path/to/camera1/*.jpg');
displayFirstImage('path/to/camera2/*.jpg');
displayFirstImage('path/to/camera3/*.jpg');
displayFirstImage('path/to/camera4/*.jpg');
?>
<script>
setTimeout("window.location.reload()", 30000);
</script>
</html>

Edit ~/.bashrc and add the following to the end of the file.

~/superscript &

Reboot the Raspberry PI and the security camera is ready to go!

Modo 10 Series

The Foundry announced the release of the [Modo 10 Series] with a small change to how updates work. [Today’s Modcast] explains the old way and the new way. The old way had the usual x01 release with the bulk of features being in the initial drop and the remaining drops being purely service packs and bug fixes. The new way will have all the drops in the series having both features and bug fixes. It seems like they are testing a slightly different business model before bringing out the popular subscription model.

Also in the forums, Brian Vowles has been chronicling a neat video project with his kids.
[Robot Attack!]

Lightweight python motion detection

Brian Flakes posted an example script in the RPI forums for how to do [lightweight python motion detection] which is useful when taking pictures with the RPI camera module.

Converted the example to work with PiCamera.

#get access to the camera
from picamera import PiCamera

import picamera.array #want to do it in memory

from PIL import Image
import requests

#import so we can invoke another script
import subprocess

#sleep so we can wait on the camera
from time import sleep

token = 'YOUR_SECURITY_TOKEN'
selector = 'group_id:SEE_THE_SELECTOR_DOCS'
threshold = 40
sensitivity = 20
firstRun = True
lastPixels = []
detected = False
showPreview = False
hidePreview = False
waitRedlight = 600
i = 0
headers = {
    "Authorization": "Bearer %s" % token,
}

# create a camera object
camera = PiCamera()

#set the image resolution
camera.resolution = (640, 480)

#rotate the camera if upside-down
#camera.rotation = 180

def Greenlight():
  payload = {
    "power": "off",
    "color": "green saturation:0.9",
    "brightness": 1.0,
    "duration": 1
  }
  try:
    response = requests.put('https://api.lifx.com/v1/lights/'+selector+'/state', data=payload, headers=headers)
  except:
    pass

def Redlight():
  payload = {
    "power": "on",
    "color": "white",
    "brightness": 1.0,
    "duration": 1
  }
  try:
    response = requests.put('https://api.lifx.com/v1/lights/'+selector+'/state', data=payload, headers=headers)
  except:
    pass

Greenlight();

while True:

  if (showPreview):
    showPreview = False
    #show preview with some transparency
    camera.start_preview(alpha=200)
    hidePreview = True

  filename = 'image'+str(i)+'.jpg'

  #save image locally
  camera.capture(filename)

  image = Image.open(filename)
  pixels = image.load()

  width, height = image.size
  #print ('width='+str(width)+' height='+str(height)+"\n");

  if (firstRun):
    firstRun = False
    lastPixels = pixels

  # Count changed pixels
  changedPixels = 0
  for x in range(width):
    for y in range(height):
      # Just check green channel as it's the highest quality channel
      pixdiff = abs(pixels[x,y][1] - lastPixels[x,y][1])
      if pixdiff > threshold:
        changedPixels += 1

  print ('changedPixels='+str(changedPixels))
  lastPixels = pixels

  if (changedPixels < 100):
    if (detected):
      detected = False
      Greenlight();
      firstRun = True
  else:
    if (detected == False):
      detected = True
      Redlight();
      sleep(waitRedlight)
      firstRun = True
      showPreview = True

  if (hidePreview):
    hidePreview = False
    #stop the preview
    camera.stop_preview()
    firstRun = True

  sleep(1)

  i = (i + 1) % 12
  

Unity WebGL and Microphone

Unity 5.3.4 [lacks Microphone support in WebGL] and I don’t see it on the [roadmap]. In the meantime, a 3rd party WebGL workaround will need to be used. I of course need it for my [word detection] plugin. The forum references a couple cool plugins. 1) [pitch detection demo] and 2) [MicrophoneWebGL.unitypackage] which will need to be adapted to work. The Unity Web Player has been deprecated and appears to just work in Firefox as you can see with [Demo 1].