Text to Speech WAV

Posted on Updated on

To make this work properly, you need to make sure you have the right speech pack installed:


The other thing, is to make sure the voices you want to use are enabled correctly.

On Windows 10 – and I have not tested this on anything else, so use it at your own risk!

You will need to run a PowerShell Script, as outlined here: https://gist.github.com/hiepxanh/8b6ad80f6d620cd3eaaaa5c1d2c660b2



$sourcePath = 'HKLM:\software\Microsoft\Speech_OneCore\Voices\Tokens' #Where the OneCore voices live
$destinationPath = 'HKLM:\SOFTWARE\Microsoft\Speech\Voices\Tokens' #For 64-bit apps
$destinationPath2 = 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\SPEECH\Voices\Tokens' #For 32-bit apps
cd $destinationPath
$listVoices = Get-ChildItem $sourcePath
foreach($voice in $listVoices)
$source = $voice.PSPath #Get the path of this voices key
copy -Path $source -Destination $destinationPath -Recurse
copy -Path $source -Destination $destinationPath2 -Recurse

Do NOT run this script more than once, because you will get double entries, and who knows if it will break things.

Basically, what it will do is read the voices you have listed as installed, and then copy some registry values to enable them in third party programs, as explained here: https://www.ghacks.net/2018/08/11/unlock-all-windows-10-tts-voices-system-wide-to-get-more-of-them/

If you don’t understand Power Shell, or Regedit, then don’t be running these scripts.


Sometimes, you may get security problems, so elevating the script may also be required.

This is what happens when the aforementioned happens.

However, when it does run, our registry entries look like this originally:

Then, they look like this:


Next steps are getting a program called Balabolka.


We are going to need the console version for this task.


If you don’t have the correct voice fix installed, you will not be able to use the correct voice you want.

I wanted to have James, but I couldn’t.


But after those fixes, James worked.

I’d also suggest that if you want to script this, it may be easier to use a config file.

-f c:\balabolka\script.txt
-w c:\balabolka\script.wav 
-n James
-s -1
-p -1
-v 95
-e 300
-d d:\Dict\rules.bxd

So, when you now run balcon.exe, you get a wave file with the text file the script.


You can listen to the weather script here without any fixes. This is the Microsoft James voice.

After fixing the paragraphs and changing the voice, this is the Microsoft Catherine voice.



It doesn’t sound great at first, but it’s workable. You can also hear where the end of the line is. This can probably fixed with automation, but it’s a bit of fun.

This is where the script came from: ftp://ftp.bom.gov.au/anon/gen/fwo/IDD10111.txt

If will not be the same as this one below, as it changes regularly, but as an example, you get the idea.

As a trial run, this is the script:

Australian Government Bureau of Meteorology
Northern Territory

Northern Territory Forecast
Issued at 5:00 am CST on Wednesday 17 June 2020
for the period until midnight CST Saturday 20 June 2020.

Warning Information
For latest warnings go to www.bom.gov.au, subscribe to RSS feeds, call 1300 659
210* or listen for warnings on relevant TV and radio broadcasts.

Weather Situation
A high pressure system over southern Australia is moving east as the next
trough approaches from WA. While the easterly flow will persist over the Top
End for the next few days, winds in the south will tend northerly, resulting in
temperatures rising again in the south. The change will move through late on
Friday, dropping temperatures in the south to around average for this time of

Forecast for the rest of Wednesday 17 June
A slight chance of showers in the far northeast Arnhem District. Sunny
elsewhere. Light to moderate east to southeast winds, fresh at times during the
morning and early afternoon, particularly south of Elliot.

Fire Danger: 
High to Very High in the Tiwi, Daly, Gregory, Carpentaria and western Arnhem

Forecast for Thursday 18 June
A slight chance of morning showers in the far northeast Arnhem District. Sunny
elsewhere. Areas of morning frost across the Simpson District. A warmer day in
the south. Light to moderate east to southeast winds, tending northeast to
northwest in the southern Tanami, western Simpson and Lasseter Districts during
the afternoon.

Forecast for Friday 19 June
A slight chance of showers in the far eastern Arnhem District. Sunny elsewhere
before some cloud develops along the eastern border during the evening. Warmer
in the south. Light to moderate east to southeast winds, tending northeast to
northwest south of Barrow Creek ahead of a south to southwest change developing
over the Lasseter District later in the day.

Forecast for Saturday 20 June
A slight to medium chance of showers in the far eastern Arnhem District. Sunny
elsewhere after early morning cloud along the eastern border. Cooler south of
Barrow Creek. Light to moderate east to southeast winds, fresh and gusty during
the morning in the Lasseter and Simpson Districts.

The next routine forecast will be issued at 4:30 pm CST Wednesday.

* Calls to 1300 numbers cost around 27.5c inc GST, higher from mobiles or
public phones.

Copyright Commonwealth of Australia 2011, Bureau of Meteorology (ABN 92 637 533
532). Users of these web pages are deemed to have read and accepted the
conditions described in the Copyright, Disclaimer, and Privacy statements

As a side note, there is also Amazon Polly and Google’s Cloud Text-to-Speech.

VirtualBox Audio on 6.1 for MacOSX solved

Posted on

After upgrading to the latest version of VirtualBox for Mac, with a Windows 7 as the client, I have struggled to get audio working with a USB audio device.

I have a Presonus Studio192 device, and it’s a fantastic piece of kit, but in the current setup, VB doesn’t want to play nice.

I am running Mojave on a 4,1->5,1.

The way around this problem with the audio not working is quite simple.

Download VoiceMeeter Banana and a program called VBAN Receptor from the Apple App store, and you should be right to go.

It’s basically and IP Audio Codec where you can route streams of the audio to different IP addresses. Rather impressive.


Screen Shot 2020-06-16 at 22.12.50

Set up the outgoing streams to the computer it should go to.

Screen Shot 2020-06-16 at 22.13.19


This costs about $10 Australian.

Screen Shot 2020-06-16 at 22.13.34


Amazing what the internet can find

Posted on Updated on

I’ve recently got a vinyl cutter, and so have gone down the path of trying things out. I bought some software to use with it, and played with a few drivers and boom, it worked… until the other day.

Yesterday, I thought I’d swap things over to my laptop on High Sierra. Suddenly, the cutter didn’t work on the MacPro, or the MacBookPro laptop. So… what do you do?

Well, originally, (I think) I had used the drivers from here, as suggested from this site

This appears to be a very common driver for mac, which is needed to emulator a serial port via USB (even though my cutter is actually coming via a USB cable anyway).

So,  today after hunting around for a very long time and eventually establishing that the software was fine and the printer was fine, it pin-pointed it to a driver problem.

The rabbit hole went a long way down, to the point where I eventually entered the apple hardware id of my cutter, and stumbled across this post who had my exact numbers and the same problem, only it was outlined with even more detail:


The link at the bottom was the final key to the solution which pointed me to the following site with a driver!


It appears to be working on the laptop for the moment in High Sierra!

I have a HL-721 Vinyl Cutter, which I think is a Chinese generic brand, and it works in the software Sure Cuts a Lot as a GoldCut JK. “Plotter Generic”, with the model being HPGL.

This site also pointed to the suggestion of using a generic cutter too: https://discourse.southlondonmakerspace.org/t/vinyl-cutter-cutter-plotter-m721/797

So, now the update for Mojave on the MacPro4,1->5,1.

I have a USB 3 Hub, with a mixture of USB 2 and 3 ports. It doesn’t want to work through the hub, using the various drivers – FTDI, ch340 etc.

But, it started working for me again, when I took it out of the hub, and ran directly in to a USB 2 port via an extension lead.

At the moment, I’ve got the FTDI driver active, and the GoldCut JK plotter set.

Strange. But, that’s computers for you!



Latest update: 20200620.

I did try and use those settings originally for the cutter, however, I found that the GoldCut settings weren’t right for me, and that while doing a test cut, there were directions given somehow, that made the cutter go on it’s own weird path.

I remembered that on the tablet I’d used a different setting. So, I changed the MacPro to the following, where it was successful!

My Cutter: Plotter Generic
Model: HPGL
Port: Auto (or the serial one) usbserial-320

Get MP3 ID3 Metadata from remote URLS

Posted on

Firstly, I didn’t create this, I’ve just making it easy to understand with a full example.

You can read more of it here, but only because of archive.org.

To begin, download this library from here: http://getid3.sourceforge.net/

when you open the zip folder, you’ll see ‘getid3’. Save that folder in to your working folder.

Next, create a folder called “temp” in that working folder that the following script is going to be running from.

Basically, what it does is download the first 64k of the file, and then read the metadata from the file.

I enjoy a simple example. I hope this helps.



$url_media = "http://domain.com/myfile.mp3"



echo $a['tags']['id3v2']['album'][0] . "\n";  
echo $a['tags']['id3v2']['artist'][0] . "\n";  
echo $a['tags']['id3v2']['title'][0] . "\n";  
echo $a['tags']['id3v2']['year'][0] . "\n"; 
echo $a['tags']['id3v2']['year'][0] . "\n";  

echo "\n-----------------\n";


echo "-----------------\n";



function getfileinfo($remoteFile)


$uuid=uniqid("designaeon_", true);
$ch = curl_init($remoteFile);
//==============================Get Size==========================//
$contentLength = 'unknown';
$ch1 = curl_init($remoteFile);
curl_setopt($ch1, CURLOPT_NOBODY, true);
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch1, CURLOPT_HEADER, true);
curl_setopt($ch1, CURLOPT_FOLLOWLOCATION, true); //not necessary unless the file redirects (like the PHP example we're using here)
$data = curl_exec($ch1);
if (preg_match('/Content-Length: (\d+)/', $data, $matches)) {
$contentLength = (int)$matches[1];
//==============================Get Size==========================//

if (!$fp = fopen($file, "wb")) {
echo 'Error opening temp file for binary writing';
return false;
} else if (!$urlp = fopen($url, "r")) {
echo 'Error opening URL for reading';
return false;
try {
$to_get = 65536; // 64 KB
$chunk_size = 4096; // Haven't bothered to tune this, maybe other values would work better??
$got = 0; $data = null;

// Grab the first 64 KB of the file
while(!feof($urlp) && $got < $to_get) { $data = $data . fgets($urlp, $chunk_size); $got += $chunk_size; } fwrite($fp, $data); // Grab the last 64 KB of the file, if we know how big it is. 
if ($size > 0) {
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RESUME_FROM, $size - $to_get);

// Now $fp should be the first and last 64KB of the file!!

catch (Exception $e) {
echo 'Error transfering file using fopen and cURL !!';
return false;

$getID3 = new getID3;
$ThisFileInfo = $getID3->analyze($filename);
return $ThisFileInfo;


RGB Lights for the MAC

Posted on Updated on

I have bought this for 3 bucks.


I’ll be combining the knowledge from this post:


And this video:


And will look at getting some RGB lights


And this

As well as some joiners.


This could be a bit of fun to brighten up my desk set up. 😀

I plan on putting these lights behind the screens, and under the desk glass to create ambient lighting, that I can change the colour of, using the computer. Should be pretty sweet.

Now to wait 2 months for them in the post…

It’s now the 28th of May, and all of the final bits have arrived. In this process, I’ve already lost the cable connectors, so I’ll look in to either getting new ones or ripping apart the office… But, testing will happen soon.

IONIC Build Errors with solutions

Posted on Updated on

Hi friends,

As I’m working on different apps, on multiple platforms and things, I thought I’d start a list of some of the errors I’d been getting, and how I solved them in IONIC.

Some of these solutions may help you. Most of these are for v3 of IONIC. Other settings vary.

I’m sure I’ll keep adding to this.

It’s a very messy file, but if Google brings you here, I hope it will help you.


Failed to install ‘cordova-sqlite-storage’: CordovaError: Using “requireCordovaModule” to load non-cordova module “q” is not supported.

Cordova error: Using “requireCordovaModule” to load non-cordova module “q” is not supported


simply add this
cordova plugin add cordova-android-support-gradle-release –variable ANDROID_SUPPORT_VERSION=27.+
and run/build again.

ERROR ITMS-90174: “Missing Provisioning Profile – Apps must contain a provisioning profile in a file named embedded.mobileprovision.”

> cordova build ios –release
CordovaError: Promise rejected with non-error: ‘ios-deploy was not found. Please download, build and install version 1.9.2 or greater from https://github.com/ios-control/ios-deploy into your path, or do \’npm install -g ios-deploy\”
at cli.catch.err (/Users/stephenmonro/ionicApps/C4I International/node_modules/cordova/bin/cordova:29:15)
at process._tickCallback (internal/process/next_tick.js:68:7)
[ERROR] An error occurred while running subprocess cordova.

cordova build ios –release exited with exit code 1.

Re-running this command with the –verbose flag may provide more information.
Analyzing dependencies
Downloading dependencies
Generating Pods project
Integrating client project
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.
Updating spec repo `master`
$ /usr/bin/git -C /Users/stephenmonro/.cocoapods/repos/master fetch origin –progress
remote: Enumerating objects: 1441, done.
remote: Counting objects: 100% (1441/1441), done.
remote: Compressing objects: 100% (236/236), done.
remote: Total 2771 (delta 1275), reused 1191 (delta 1191), pack-reused 1330
Receiving objects: 100% (2771/2771), 320.66 KiB | 767.00 KiB/s, done.
Resolving deltas: 100% (1828/1828), completed with 553 local objects.
From https://github.com/CocoaPods/Specs
5bdc3da58dc..70702dce5ff master -> origin/master
$ /usr/bin/git -C /Users/stephenmonro/.cocoapods/repos/master rev-parse –abbrev-ref HEAD
$ /usr/bin/git -C /Users/stephenmonro/.cocoapods/repos/master reset –hard origin/master
HEAD is now at 70702dce5ff [Add] TidySplits 1.0.4
Updating spec repo `trunk`

CocoaPods 1.9.0.beta.3 is available.
To update use: `sudo gem install cocoapods –pre`
[!] This is a test version we’d love you to try.

For more information, see https://blog.cocoapods.org and the CHANGELOG for this version at https://github.com/CocoaPods/CocoaPods/releases/tag/1.9.0.beta.3

The file /Users/stephenmonro/ionicApps/C4I International/platforms/ios/Christians for Israel.xcworkspace does not exist.
Problem solved here: unplug the ipad, or the device.


I experience this error if my phone is connected to my computer (via cable) when I am running the build command.

Simply unplugging the cable solved the problem.


npm update

[app-scripts] fs.js:114
[app-scripts] throw err;
[app-scripts] ^
[app-scripts] Error: ENOENT: no such file or directory, scandir ‘/Users/stephenmonro/ionicApps/wpimportsqlite/node_modules/node-sass/vendor’
[app-scripts] at Object.readdirSync (fs.js:785:3)


node ./node_modules/node-sass/scripts/install.js


stephenmonro@SMMMacPro:~/ionicApps/wpimportsqlite$ ionic serve
> ionic-app-scripts serve –address localhost –port 8101 –livereload-port 35730 –dev-logger-port 53704 –nobrowser
[app-scripts] [23:24:14] ionic-app-scripts 3.2.4
[app-scripts] [23:24:14] watch started …
[app-scripts] [23:24:14] build dev started …
[app-scripts] [23:24:14] Proxy added:/wp-json => https://www.c4israel.org/wp-json
[app-scripts] [23:24:14] Proxy added:/resources/app/pdf => https://www.c4israel.com.au/resources/app/pdf/
[app-scripts] [23:24:14] clean started …
[app-scripts] [23:24:14] clean finished in 2 ms
[app-scripts] [23:24:14] copy started …
[app-scripts] [23:24:14] deeplinks started …
[app-scripts] [23:24:15] deeplinks finished in 336 ms
[app-scripts] [23:24:15] transpile started …
[app-scripts] [23:24:22] typescript: node_modules/@types/node/events.d.ts, line: 21
[app-scripts] ‘=’ expected.
[app-scripts] L20: function on(emitter: EventEmitter, event: string): AsyncIterableIterator<any>;
[app-scripts] L21: const captureRejectionSymbol: unique symbol;
[app-scripts] ‘=’ expected.
[app-scripts] [23:24:22] typescript: node_modules/@types/node/events.d.ts, line: 32
[app-scripts] L32: const errorMonitor: unique symbol;
[app-scripts] [23:24:23] typescript: node_modules/@types/node/repl.d.ts, line: 361
[app-scripts] ‘=’ expected.
[app-scripts] L361: const REPL_MODE_SLOPPY: unique symbol;
[app-scripts] ‘=’ expected.
[app-scripts] [23:24:23] typescript: node_modules/@types/node/repl.d.ts, line: 367
[app-scripts] [23:24:23] typescript: node_modules/@types/node/util.d.ts, line: 26
[app-scripts] L367: const REPL_MODE_STRICT: unique symbol;
[app-scripts] ‘=’ expected.
[app-scripts] L25: let replDefaults: InspectOptions;
[app-scripts] L26: const custom: unique symbol;
[app-scripts] ‘=’ expected.
[app-scripts] L120: namespace promisify {
[app-scripts] L121: const custom: unique symbol;
[app-scripts] [23:24:23] typescript: node_modules/@types/node/util.d.ts, line: 121
[app-scripts] [23:24:23] typescript: node_modules/@types/node/events.d.ts, line: 21
[app-scripts] Cannot find name ‘unique’.
[app-scripts] L20: function on(emitter: EventEmitter, event: string): AsyncIterableIterator<any>;
[app-scripts] L21: const captureRejectionSymbol: unique symbol;
[app-scripts] [23:24:23] typescript: node_modules/@types/node/events.d.ts, line: 21
[app-scripts] Cannot find name ‘symbol’. Did you mean ‘Symbol’?
[app-scripts] L20: function on(emitter: EventEmitter, event: string): AsyncIterableIterator<any>;
[app-scripts] L21: const captureRejectionSymbol: unique symbol;
[app-scripts] Cannot find name ‘unique’.
[app-scripts] [23:24:23] typescript: node_modules/@types/node/events.d.ts, line: 32
[app-scripts] L32: const errorMonitor: unique symbol;
[app-scripts] [23:24:23] typescript: node_modules/@types/node/events.d.ts, line: 32
[app-scripts] Cannot find name ‘symbol’. Did you mean ‘Symbol’?
[app-scripts] L32: const errorMonitor: unique symbol;
[app-scripts] Cannot find name ‘unique’.
[app-scripts] [23:24:23] typescript: node_modules/@types/node/repl.d.ts, line: 361
[app-scripts] L361: const REPL_MODE_SLOPPY: unique symbol;
[app-scripts] Cannot find name ‘symbol’. Did you mean ‘Symbol’?
[app-scripts] [23:24:23] typescript: node_modules/@types/node/repl.d.ts, line: 361
[app-scripts] L361: const REPL_MODE_SLOPPY: unique symbol;
[app-scripts] Cannot find name ‘unique’.
[app-scripts] [23:24:23] typescript: node_modules/@types/node/repl.d.ts, line: 367
[app-scripts] [23:24:23] typescript: node_modules/@types/node/repl.d.ts, line: 367
[app-scripts] L367: const REPL_MODE_STRICT: unique symbol;
[app-scripts] Cannot find name ‘symbol’. Did you mean ‘Symbol’?
[app-scripts] L367: const REPL_MODE_STRICT: unique symbol;
[app-scripts] Cannot find name ‘unique’.
[app-scripts] L25: let replDefaults: InspectOptions;
[app-scripts] [23:24:23] typescript: node_modules/@types/node/util.d.ts, line: 26
[app-scripts] [23:24:23] typescript: node_modules/@types/node/util.d.ts, line: 26
[app-scripts] L26: const custom: unique symbol;
[app-scripts] Cannot find name ‘symbol’. Did you mean ‘isSymbol’?
[app-scripts] L25: let replDefaults: InspectOptions;
[app-scripts] L26: const custom: unique symbol;
[app-scripts] Cannot find name ‘unique’.
[app-scripts] L120: namespace promisify {
[app-scripts] L121: const custom: unique symbol;
[app-scripts] [23:24:23] typescript: node_modules/@types/node/util.d.ts, line: 121
[app-scripts] [23:24:23] typescript: node_modules/@types/node/util.d.ts, line: 121
[app-scripts] Cannot find name ‘symbol’.
[app-scripts] L120: namespace promisify {
[app-scripts] L121: const custom: unique symbol;

[INFO] Development server running!

Local: http://localhost:8101

Use Ctrl+C to quit this process

[INFO] Browser window opened to http://localhost:8101!

[app-scripts] [23:24:23] watch ready in 8.56 s
[app-scripts] [23:24:23] copy finished in 8.53 s

npm install typescript@2.7.2


[23:51:47] typescript error
Cannot find type definition file for ‘@types’.

[23:51:47] ionic-app-script task: “build”
[23:51:47] Error: Failed to transpile TypeScript
Error: Failed to transpile TypeScript
at errorCheckProgram (/Users/stephenmonro/ionicApps/wpimportsqlite/node_modules/@ionic/app-scripts/dist/aot/aot-compiler.js:119:39)
at Object.<anonymous> (/Users/stephenmonro/ionicApps/wpimportsqlite/node_modules/@ionic/app-scripts/dist/aot/aot-compiler.js:89:21)
at step (/Users/stephenmonro/ionicApps/wpimportsqlite/node_modules/@ionic/app-scripts/dist/aot/aot-compiler.js:32:23)
at Object.next (/Users/stephenmonro/ionicApps/wpimportsqlite/node_modules/@ionic/app-scripts/dist/aot/aot-compiler.js:13:53)
at fulfilled (/Users/stephenmonro/ionicApps/wpimportsqlite/node_modules/@ionic/app-scripts/dist/aot/aot-compiler.js:4:58)
[ERROR] An error occurred while running subprocess ionic-app-scripts.


What seems to fix it is to add
“types”: []
to the
tsconfig.json’s compilerOptions.


High Sierra Security Update Jan 2020 Problem

Posted on Updated on

Today, I followed the update procedure of Apple to update to the latest MacOS Security updates. And… it didn’t go so well…

I tried the old PRAM reset and also an SMC reset as well. It still didn’t work. I got in to the recovery part as well, and was able to do a first aid on the disk. It all checked out well.

I also tried Safe Mode, but that didn’t really work properly, but it did spit out a lot of good information. I spotted something along lines of it hanging on a KEXT or similar.

Nothing really worked and it just stayed on this window, it basically looks like it’s hung…

After a few hours, nothing.

So I went to an Apple store, and asked for the most geeky non-retail person. They didn’t have what I needed, so have now booked in to see a genius.

I came home and thought I’d try and fix it again.

I came across this website.


So, instead I tried this and logged in via Single User mode and followed this section.

The OS X Fix You’ve Been Looking For

I was ultimately able to surmise that the issue was an incompatible kernel extension (kext file). After booting into Recovery Mode, I opened Terminal. First I mounted the filesystem as read write, then navigated to /Volumes/Macintosh HD/Library/Extensions, created a new folder named “Unsupported” and moved all the kext files into it, then rebooted.

Note: see the updated script at the very bottom of this post to automatically remove non-default kexts. If you have renamed your hard drive to something other than “Macintosh HD” use the new name in the following commands.

mount -rw /
cd /Volumes/Macintosh\ HD/Library/Extensions/
mkdir Unsupported
mv *.kext Unsupported


So, in short, it was as I suspected, to be a suspect KEXT file.

This will get you out of trouble.



I hate asynchronous JS programming

Posted on Updated on

This has to be the biggest problem I face when using JS.

It’s not like VB, VBScript, BAT, BAS, C# or other serial, linear programming languages.

It drives me crazy.

I’m still of the opinion that all code should still be sequential by default, and if you want a function to be async, then you should just tell that specific call to be async, rather than the other way around. An opt in, rather than “you’re already in and tough luck”.

To make like easier (and I’ve stolen this code to post here, as it makes life easier and so I can find it again later) here is some code of a working practical example.


Serial or Chaining Flow

If you want to execute different promise methods sequential i.e. execute one by one, it is easy using Async/Await and the code looks like synchronous.

async function SerialFlow(){
let result1 = await doJob(1,1);
let result2 = await doJob(2,2);
let result3 = await doJob(3,3);
let finalResult = result1+result2+result3;
return finalResult;

In above method first 1 is executed and wait for one sec then 2 is started wait for 2 seconds after that 3 started to execute. 1,2,3 are executed sequentially, hence the total time is 6 seconds.

Console Output:

Start: 1
End: 1
Start: 2
End: 2
Start: 3
End: 3


Just about every other example online gives non-practical examples and use promises, observables, awaits, asyncs, call-back hell, jargon that mostly doesn’t make sense. I hope this very simple example will help you.


Here is my very crude example of partially working code, of which you can see there are things going on.

async function getpostcoderegion(state)
  var dataselection = document.getElementById(“dataselection”).value;
  var dateparams = “&date=” + dataselection;
// Confirm as CITY
// Confirm as REGIONAL
  var params = “state=” + state + dateparams;
  var xhttp =  new XMLHttpRequest();
    xhttp.onreadystatechange = await function() {
    if (this.readyState == 4 && this.status == 200) {
      citystations = JSON.parse(xhttp.responseText);
  xhttp.open(“POST”, “getpostcodecitystate.php”, true);
  xhttp.setRequestHeader(‘X-Requested-With’, ‘XMLHttpRequest’);
  xhttp.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);
  return 1;

async  function postcodeboundariesshow(state_location)

  // Collected the postcodes of those that are for the city/metor areas in that state.
    var file_location = “../../geo_json/” + state_location + “.postcode.json”;
 geojsonLayer[state_location] = new L.GeoJSON.AJAX(file_location, {
    onEachFeature: onEachFeature,
    “fillOpacity”: .05,
    color: “#F00”,
    weight: 1,
   return “2”;


async function postcodeboundaries(state_location)

  // Collected the postcodes of those that are for the city/metor areas in that state.
    let a = await getpostcoderegion(state_location);
    let b = await postcodeboundariesshow(state_location);

Ionic 3 Background Geolocation

Posted on

It’s taken a long time to get to this stage, but this is just the start…

After having followed the instructions on this site, I got a long way.

But, I also only got so far as well… Here is a copy of my “home.ts” file for an app.


import { Component } from '@angular/core';
import { NavController, Platform } from 'ionic-angular';
import { BackgroundGeolocation, BackgroundGeolocationConfig, BackgroundGeolocationResponse, BackgroundGeolocationEvents } from '@ionic-native/background-geolocation';
import { LocalNotifications } from '@ionic-native/local-notifications';

selector: 'page-home',
templateUrl: 'home.html'
export class HomePage {

config: BackgroundGeolocationConfig = {
desiredAccuracy: 10,
stationaryRadius: 20,
distanceFilter: 30,
debug: true, // enable this hear sounds for background-geolocation life-cycle.
stopOnTerminate: false, // enable this to clear background location settings when the app terminates

missionCode: string = "";
userId: string = "";

constructor(public navCtrl: NavController,

private plt: Platform, 
private backgroundGeolocation: BackgroundGeolocation,
public globals: GlobalsProvider,
private localNotifications: LocalNotifications) {

if(this.plt.is('core') || this.plt.is('mobileweb')) {

// NO. It's a browser.
// Use a different GPS method.

} else 
// YES. It's a a compilerd app.

.then(() => {

subscribe((location: BackgroundGeolocationResponse) => {


// IMPORTANT: You must execute the finish method here to inform the native plugin that you're finished,
// and the background-task may be completed. You must do this regardless if your HTTP request is successful or not.
// IF YOU DON'T, ios will CRASH YOUR APP for spending too much time in the background. 
this.backgroundGeolocation.finish(); // FOR IOS ONLY



startBackgroundGeolocation() {
// start recording location

stopBackgroundGeolocation() {
// If you wish to turn OFF background-tracking, call the #stop method.

// Schedule a single notification
id: 1,
text: JSON.stringify(data),
sound: 'file://sound.mp3',
data: { secret: "key" }



My packages.json file looks like this:

"name": "My App",
"version": "0.0.1",
"author": "Ionic Framework",
"homepage": "http://ionicframework.com/",
"private": true,
"scripts": {
"start": "ionic-app-scripts serve",
"clean": "ionic-app-scripts clean",
"build": "ionic-app-scripts build",
"lint": "ionic-app-scripts lint"
"dependencies": {
"@angular/animations": "5.2.11",
"@angular/common": "5.2.11",
"@angular/compiler": "5.2.11",
"@angular/compiler-cli": "5.2.11",
"@angular/core": "5.2.11",
"@angular/forms": "5.2.11",
"@angular/http": "^5.2.11",
"@angular/platform-browser": "5.2.11",
"@angular/platform-browser-dynamic": "5.2.11",
"@auth0/angular-jwt": "^1.2.0",
"@babel/core": "^7.8.4",
"@ionic-native/background-geolocation": "^4.20.0",
"@ionic-native/core": "~4.11.0",
"@ionic-native/geolocation": "^4.20.0",
"@ionic-native/http": "^4.20.0",
"@ionic-native/local-notifications": "^4.20.0",
"@ionic-native/splash-screen": "~4.11.0",
"@ionic-native/status-bar": "~4.11.0",
"@ionic/storage": "^2.2.0",
"cordova-android": "^7.1.1",
"cordova-browser": "^6.0.0",
"cordova-plugin-advanced-http": "^2.4.0",
"cordova-plugin-badge": "^0.8.8",
"cordova-plugin-device": "^2.0.3",
"cordova-plugin-file": "^6.0.2",
"cordova-plugin-geolocation": "^4.0.2",
"cordova-plugin-ionic-keyboard": "^2.2.0",
"cordova-plugin-ionic-webview": "^2.5.3",
"cordova-plugin-local-notification": "^0.9.0-beta.2",
"cordova-plugin-mauron85-background-geolocation": "^3.0.1",
"cordova-plugin-splashscreen": "^5.0.3",
"cordova-plugin-whitelist": "^1.3.4",
"cordova-sqlite-storage": "^4.0.0",
"emulator": "0.1.0",
"glob": "^7.1.6",
"ionic-angular": "3.9.2",
"ionicons": "3.0.0",
"leaflet": "^1.6.0",
"leaflet-ant-path": "^1.3.0",
"leaflet-draw": "^1.0.4",
"leaflet-gps-tracker": "^1.2.1",
"leaflet-polyline": "0.0.2",
"leaflet.freedraw": "^2.0.1",
"native-run": "^0.3.0",
"node-sass": "^4.13.1",
"resolve": "^1.15.0",
"rxjs": "5.5.11",
"sw-toolbox": "3.6.0",
"zone.js": "0.8.26"
"devDependencies": {
"@ionic/app-scripts": "^3.2.4",
"typescript": "~2.6.2"
"description": "The best way to manage your searches from an emergency management control point.",
"cordova": {
"plugins": {
"cordova-plugin-geolocation": {
"cordova-plugin-whitelist": {},
"cordova-plugin-device": {},
"cordova-plugin-splashscreen": {},
"cordova-plugin-ionic-webview": {},
"cordova-plugin-ionic-keyboard": {},
"cordova-sqlite-storage": {},
"cordova-plugin-advanced-http": {},
"cordova-plugin-mauron85-background-geolocation": {},
"cordova-plugin-local-notification": {}
"platforms": [


This code is a little old, but please note, the version numbers in my packages.json file.

Leaflet Performance issues

Posted on Updated on

I’m really enjoying working with Leaflet at the moment, but this problem had plagued me for days, where all of a sudden, my performance levels dropped to almost nothing.

Basically I went from this:

maxZoom: 111,
drawControl: true,
}).on('locationfound', (e) => {

this.locationdata = { "coords":{"latitude": e.latlng.lat, 
"longitude": e.latlng.lng,
"accuracy" : e.accuracy, 
"altitude" : e.altitude, 
"heading" : e.heading,
"speed" : e.speed,
"timestamp" : e.timestamp



To this:

maxZoom: 111,
drawControl: true,
}).on('locationfound', (e) => {

this.locationdata = { "coords":{"latitude": e.latlng.lat,
"longitude": e.latlng.lng,
"accuracy" : e.accuracy,
"altitude" : e.altitude,
"heading" : e.heading,
"speed" : e.speed,
"timestamp" : e.timestamp


What’s the difference you say?

” watch:true,”

Basically, if you have have this running like this, it will keep on checking the GPS signal in the background, and eventually cripple everything, because your phone device can’t keep up with the app. GPS time-outs will occur and things won’t complete. So, if you remove the watch:true statement, things will still work well, and you can call it every second, or every 10 seconds, or whatever your tracking needs are.

My full issue was that exponentially, the app was just slowing down to a complete halt and anything to do with the map would slow and stop working. It would begin fine, but within a few minutes, the app was unusable.

So, this is my (partial) solution. It should be enough to help you get by.

I’ve found it’s easier to do something like this:

this.subscr = Observable.interval(1000) 
.flatMap(() => this.getData())
.subscribe(data => { 
//console.log("App 1 second heartbeat"); 
// Call the GPS tracker bit
if(this.trackedRoute.length >0)


So, after a couple of days thinking it was layer and mapping problems (with showing hiding markers or tracking lines and rewriting that entire part), and optimising the app even more, I think it’s pretty good now. This will be more or less confirmed over time though.

You can draw a tracking line like this too:

current_positionTrack: any [];

// Show the current location on the map
if (this.current_positionTrack != undefined) 

this.current_positionTrack = leaflet.polyline(path, {color: 'red', weight: 1, opacity: 0.7, smoothFactor: 1});

And even have a marker that stays on the screen on your location too, like this:

marker = null;

some_other_function_etc () //or whatever

// Probably should go after this in the GPS tracker bit:
// }).on('locationfound', (e) => {
// You'll figure it out.
 if (!this.marker) {
  this.marker = leaflet.marker(e.latlng).addTo(this.map);

 if(e.latlng != null)