ARM Development Summit

Like many conferences in 2020, ARM’s conference on development is available online. The videos of the summit are online until November 28th, but if you want to see them, you will need to register to see them by October 28. To register, go to this site. The conference list having the following tracks for their presentations.

AI in the Real World

Gain experience with the tools and techniques that will shape the future of AI and solve real-world challenges.

Building the IoT

Dive into transformative IoT technologies that train to take your ideas from concept through production.

Chip Design Methodology

Beyond silicon, see how to deliver your designs for more efficient targeted solutions.

Cloud Native Developer Experience

From operating systems to CI/CD tooling and more, learn cloud-native development for scalable architectures.

Creating the Next Generation of Interactive Experiences

Hear how to apply advanced technologies like ML and AR to your next mobile development project.

Infrastructure of Modern Computing

Learn how to make the most of the ARM architecture in High-Performance Computing networking and storage.

Tech for Global Goals: The World’s Largest To-Do List

Learn how organizations deploy technology to tackle some of the world’s most pressing problems

The Journey to Autonomous

Explore some of today’s most interesting engineering challenges from real-time signal processing, machinery control, embedded vision, and more.

Follow me on

Twitter: @j2inet
Instagram: @j2inet
Facebook: j2inet
YouTube: j2inet

Installing Visual Studio Code on Raspberry Pi and NVIDIA Jetson

While it is possible to run Visual Studio Code on a Raspberry Pi or a NVIDIA Jetson, the process previously had a few challenges. With one method, a user could grab the code from Microsoft and compile it for their device. This was time consuming and required that a person perform some steps to be set up for development. An easier method involved acquiring a build from a third party source. The issue there is the user must trust the third party source. Now these are no longer issues because Microsoft provides ARM binaries for Visual Studio Code. The installation can be done on both devices with the same steps.

To install VS code, navigate to and click on the Learn More link on the Visual Studio Code box. From there, if you click on Other Platforms you will see all of the downloads that are available for Visual Studio Code. For the Jetson series of hardware you will want to download the ARM64 deb installer. For Raspberry Pi, if you are using the a 64-bit OS installation grab an ARM64 build. Otherwise grab the ARM build.

After the build has downloaded, open a terminal and navigate to the folder where you saved the ARM file. From the terminal type the following command.

sudo dpkg -i name_of_file.deb

An actual file name should replace name_of_file.deb. After a minute or two the installation completes. You can start VS Code from the command line by typing the command code and pressing Enter. You can also find it within your program files. Videos of the installation are available below.

Video of Installation for Raspberry Pi
Video of Installation for NVIDIA Jetson

Instagram LogoLinked In

Web Conferences with a DSLR/Video Camera

I decided to make the switch from using my Microsoft LifeCam or the camera built into the computer to using my DSLR. When I made the switch, I didn’t disclose that I was using a different camera. I wanted to see if anyone noticed. It was noticed, and almost distractingūüėä! I received a few questions from coworkers from what I was doing different. In response, I’ve made this post and a video. In the video at the end of this post, you can see comparisons of quality for the cameras that I had used.

Note that some cameras can already be use as web cameras by downloading a firmware update or other camera specific software. You may want to check if your camera has this functionality available before making any purchases.

Canon 5D Mark II with Remote Focusing Motor

There are two primary pieces of hardware that are needed. Everything else is optional or can be improvised. The first is a camera that will produce clean HDMI output. By “Clean” I mean without the user interface elements on it. For a camera that supports this you may have to change a setting instructing it not show the UI elements on the output. You also will want to be able to disable the power saving features of the camera so that it does not power off while using it.

The second item that you need is an HDMI capture device that the computer “sees” as a Web Cam. Right now, the popular unit is the CamLink 4K. I’ve used a few of these for my day job and while they work, they also sometimes have errors that is just plain annoying. The device sometimes looses video signal. When it does, the only way I’ve been able to get it back is to unplug it and plug it back in. Another option that is not out yet is an HDMI capture decide from ATMOS. This device isn’t out yet, so I can’t recommend on its reliability. But I think it is worth considering.

Cam Link 4K HDMI Capture Device

The basic setup is to connect the HDMI capture device to the camera, turn the camera on, and plug it into a computer to use it as a web camera. That should be it, everything should work with no software installation required. For my setup, I do have additional hardware. While a table-top tripod would work, I prefer not to have fixtures take up space on my desk. To minimize the space being consumed I’m using a photography clamp to set an anchor point on the desk. A tripod extension attached to the clamp supports the camera. So that I can have the camera positioned as needed, I have a ball head between the camera and the tripod extension.

My camera is an older unit. It is a Canon 5D Mark III. A feature this camera does not have is refocusing automatically. Though even if it did, since my favourite lenses are fully manually, I would not have access to autofocus anyway. A potential focusing issue (since I prefer a shallow depth of field with my background blurred out) is that manual focusing on one’s self can be difficult. To adjust the focus I have to move to be able to reach the camera. But if I move then I am no longer in the field of vision where I need to be to know whether or not the camera is properly focused. The solution that I’m using for this the Nucleus-N wireless focusing unit. The Nucleus-N is composed of a wireless focusing knob and a motor that attached to the camera. When the knob is turned, the motor reacts and adjusts the lens.

If I were trying to setup this up from scratch and had to acquire a camera today, I would consider a mirrorless camera. The Canon EOS R and the Sony Alpha a7 would be at the top of my list.

Posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.

Debugging Android Applications over WiFi

I was recently working on an application that used the device’s accelerometer to extract information from the way that a person walks. While I was aware that it was possible to debug applications over WiFi, until now it wasn’t something that was absolutely needed. If I needed to get up and move a bit for an application, I had just used a longer USB cable. With this application it was essential that I want the way that I normally do. There was no way to do that with a USB cable connected to the device. Instead, it was necessary to use WiFi debugging.

Another reason why one might want to debug over WiFi simply to charge a device; some computers output a disappointing amount of current over their USB ports. For some applications, the device’s battery could continue to diminish as it is being used while connected to a computer. Using a higher wattage charge may be necessary if only to maintain the current battery amount.

For devices running Android 10 and earlier, making the network connection is easy. Start by making a USB connection. To ensure that there is a connection established use the following command.

adb devices

You should see your device listed. If it is, the next step is to establish a connection over the network. Ensure that your device and the computer being used for debugging are on the same network and subnet. Enable network debugging on your computer using the following command.

adb tcpip 5556

Here 5555 is the port number that will be used. You can use a different port number if you like. Using the IP address of your android device, you can establish a connection with the following command.

adb tcpip

If all goes well, a message will be received that the device is connected. The device can now be physically disconnected from the computer. It will remain connected to the computer over the network connection.

Within Android Studio or adb if left connected the device will show twice.

Both devices showing within Android Studio

The device will continue to show as a connection until manually disconnected. To manually disconnect use the following command.

adb disconnect

Power Options for the Raspberry Pi 4

The Raspberry Pi has a few more power options than what one might gather from a quick glance. With the exception of the computer modules (which will get no further mention here) the Pis have a USB port for providing power. The Pi-4 has a USB-C port while the other units use micro-USB. In most cases having a 5-volt power supply with a the appropriate USB interface is sufficient. Using the USB interface, the Pi can be powered through a phone charger. This includes portable chargers, which might be used if the Pi needs to be placed where outlets are not available or if they must be movable. The USB port isn’t the only way to power the Pi though.

View this content in Video Form

Another way of powering the Pi is through the 40-pin connector. There are pins labeled 5V and GND. these pins are often used as a voltage output. But these pins can also be used as a voltage input. Applying appropriate voltage to these pines will power the Pi on. In addition to applying 5-volts directly, there are also Pi-hats made for interfacing to these pins. On the Pi-4 and Pi-3, just behind the Ethernet connector, there are 4 pins. These pins connect to the unused connections in the Ethernet jack. With a Power over Ethernet (PoE) hat, voltage supplied over these pins can be passed through a voltage regulator and then fed into the Pi.

Pi PoE Pins

To use this there are a few conditions that must be met. If you are considering this this solution then you will undoubtedly be using the Pi with a wired network connection. You also need a means of injecting power into the network. Some routers have this functionality build in. For routers that do not, there are various forms of PoE power injectors. With this solution a headless Pi only needs one cable for providing a network connection and a the power. Such hats are available in a number of form-factors. My preference is towards the one of the minimalist PoE adapters.

This adapter leaves many of the other pins open. If cooling is needed, the official Raspberry Pi PoE hat also has a fan.

Official Raspberry Pi PoE Hat

If you have a Pi that doesn’t support PoE, you are not out of luck! You can still take advantage of it with adapters for extracting power from the extra lines and routing it to the USB input on your Pi.

PoE Extractor with Micro-USB

Another way of powering a Pi is with batteries. While it is possible to take consumer batteries (AA or AAA batteries) and power a Pi with those, I would not suggest it. There are options available with higher capacities and other features that are worth considering. In looking at a battery solution not only might you want to consider the battery capacity, but the inclusion of a real time clock and the ability to query the power level of the batteries. The most basic solutions only provided power and a USB port for charging the battery.

Many of the solutions use 18650 batteries. So named because they are 18mm in diameter and 65mm long. These cells look a lot like enlarged AA batteries. Even if you don’t recognize them, you’ve probably encountered these batteries before in laptop computers. Unlike the diminutive consumer batteries of similar shape, these cells rate at having a nominal voltage of 3.7 volts each. With two batteries together they are able to meet and exceed the 5-volt power requirement for the Pi. Power regulation circuits within the battery adapters ensure that the power delivered to the Pi doesn’t exceed 5-volts.

Laptop battery with the contents shown.
A laptop battery that has been opened up to show the 18650 batteries from the inside.

One of my favourite is the Geekworm X728. This unit contains a real-time clock and has scripts available for probing the state of the battery. The unit allows settings for having the pi automatically startup when power is applied and shutting down when when the battery level is low. For increasing the battery capacity, additional pairs of batteries can be added to the X728-A2 . The X728-A2 is made only for connecting to the X728 and add additional batteries. Though if you have the know-how, you can connect additional batteries in parallel to the ones in the X728. The board shows the power level through three LEDS on the side. There’s also a dedicated power-button on the board for powering up and shutting down.

X728 In an Acrylic Case

In close second is the PiJuice. Right now the PiJuice is a lot more expensive than the X728 at almost twice the price. But it has an additional feature; the PiJuice allows scripts to be scheduled to run under specific power or time conditions. While the battery included with the PiJuice has lower capacity than a pair of 18650 batteries, there are use cases under which it could have longer usage before requiring a charge. On the PiJuice the Pi can be put to sleep, consuming much less power, and then wake up to perform some work and go back to sleep.

The PiJuice mounted to the back of a Pi 3B

The last battery kit I want to mention is sold under various names. When I ordered one, it was branded under GeekPi. While that specific SKU is no longer available, the same unit is available branded from MakerHawk. It is often described as a UPS (Uninterruptible Power Supply). It is the least expensive of the battery kits, costing less than half the price of either of the other two. But it doesn’t have any way for the pi to detect the battery level or a way to have the Pi react to power events. It only provides power and nothing more. Like the X728, one could connect additional batteries in parallel to increase the available energy.

UPS mounted to the underside of a Raspberry Pi 4

All of the battery solutions can also function as a UPS; if external power fails your Pi would be able to continue working. I’ve been able to keep the Pis running for hours at a time (days in the case of the Pi Juice on a wake/sleep schedule). I love the overall compactness of the the battery solutions made for the Pi. Some time in the future I plan to present one of the Pi based solutions that I made using the batteries.

Instagram LogoLinked In

Posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.

USB Networking with the Pi


I stumbled upon a thread in the Raspberry Pi forums about enabling networking on the USB-C port on the Raspberry Pi 4. At first glance I thought this would be about networking with a USB-C to Ethernet dongle. It’s not. It is about configuring the Raspberry Pi to present as a network adapter when connected to another device with a USB-C cable. While this might sounds like a rather pedestrian capability at first it is something that has a lot of potential. I see using this when I want to do development on the Pi and I’m in an environment in which a network isn’t available (such as when I’m on a long plane trip) or when there’s a network but I just can’t connect the Pi to it (such as on a corporate network).¬† Additionally since I expect my Android tablet to loose it’s ability to run Linux this provides a portable dev environment in which I can put the capabilities that I need.

The basic steps in what to do can be found on this thread posted by the user thagrol.  The steps are simple. I am re-posting the steps here.

  1. Open /boot/config.txt and add the line
  2. Open /boot/cmdline.txt and append the following
  3. Reboot the Pi

After doing these steps when the Pi is connected to a computer the computer will see it as a networking device. If you list the network adapters on the Pi you will see a new network adapter with the name usb0.

thagrol notes that the mac address generated for both sides of this virtual network adapter will be different every time that the service is started. This can cause issues when using DHCP.   He provides a solution in the form of a script that will generate a set of MAC addresses based on a unique identifier in the Raspberry Pi.  After cloning the GIT repository for the script run it as root.

sudo ./ --test


Once the addresses are generated they can be added to /boot/cmdline.txt. The addition will follow this format.

g_ether.host_addr=HOST_MAC_ADDRESS g_ether.dev_addr=DEVICE_MAC_ADDRESS

In my case  the additional entry will be

g_ether.host_addr=02:00:27:75:0a:a5 g_ether.dev_addr=06:00:27:75:0a:a5

I’m going to set a static IP on my pi. To do this the file /etc/dhcpcd.conf must be edited. Scrolling to the bottom of the file commented out is a demonstration of how to set a static address.


For the USB interface I’e added two lines to the bottom of this file

interface usb0
static ip_address=

After rebooting the Pi now shows this address for the USB network interface. I’m connecting to my pi with a Windows machine. After physically connecting the device a static IP address was set on the Windows side.


To ensure that things are working I started off trying to ping the device and received positive responses.


Pinging with 32 bytes of data:
Reply from bytes=32 time<1ms TTL=128
Reply from bytes=32 time<1ms TTL=128
Reply from bytes=32 time<1ms TTL=128
Reply from bytes=32 time<1ms TTL=128

To try something a bit more functional I tried opening a folder on the Pi using Visual Studio Code running from my computer. Success!


In theory this could work with a phone or other mobile device. The restricting factor is whether someone’s mobile device allows changing settings on external network adapters. Many will allow communication over such adapters, but a much smaller set will allow you to change the settings.

Editing a C# file on the Pi over SSH from a Chromebook

Something to note though, when using this solution on a mobile device there is a significant power drain, which makes sense; the mobile device’s battery is now working for two. There are a few ways to mitigate this but they break down to either batteries or external power. For batteries someone could add a battery to the Pi itself. There are a number of solutions that work well. I prefer PiJuice since it comes with some other options on invoking behaviours based power levels or time. Unfortunately at the time that I am writing this (during the 2020 shelter-at-home directive) this specific unit looks to be unavailable.

There are many other Pi batteries available. If you shop for one make sure that you purchase one that provides power through the headers or through pogo pens. Some provide power through the USB-C connector, which you need to keep available to act as a network connection.  Also give consideration to the connector used to charge the unit you select. You might prefer micro-USB or USB-C.  I would suggest not overclocking your Pi if it is running off of a battery. Some batteries might not be compatible with some types of cases. Ex: there is a Pi case that is essentially a heatsink that wraps the entire device. That would not work with with a power solution that uses pogo pens.

twitterLogofacebookLogo  youtubeLogo

Raspberry Pi 4

GeeekPi Raspbery Pi 4 UPS Power Supply

4PK 18650 Battery

Hearing on Online Platforms and Market Power

Today, July 29, 2020, the CEOs of four technology companies will meet virtually with a House subcommittee about their market power. Some have asserted that these companies have monopolies or near-monopolies. Time Cook of Apple, Mark Zuckerberg of Facebook, Sundar Pichai of Google, and Jeff Bezos of Amazon will be present. There was a push for Jack Dorsey of Twitter to attend from representative Jim Jordon of Ohio, but he is not expected to attend.

These companies are being investigated for their market dominance. For Apple, a key issue is that the only method of distribution to iOS devices is through the Apple App Store. While it is the case for a number of consumer devices that the device manufacturer is the only entity that can decide if an application will be available to the device (ex: Nintendo licensing games for the Switch, Sony for the Playstations, Microsoft for the Xbox) some entities have asserted that the arrangement is unfair. Most notably Spotify made a complaint about the revenue split terms for the Apple App Store and being disallowed from advertising other ways that a customer may purchase its service that do not involve Apple.

Amazon’s use of data that is has collected is in question. It’s combination of customer data, seller data, and its intelligence capabilities give it a significant advantage. Not only does Amazon sell items from third parties, it also produces its own products that compete with those providers. There is a question of it being fair.

For Facebook’s acquisition strategies are in question. And it also has a large advertising network that is being scrutinized.

Google, in addition to having the worlds most popular search engine, also has a wide advertising network. Google also gained the attention of regulators in the European Union because if its search engine giving preference to Google products for some types of searches.

Live-streaming of the hearing will be available on YouTube at the following starting at 12:00PM Eastern Time today, 29 July 2020.


This isn’t the first hearing that the committee has had, but it will be the first one at which these CEOs have all been present. In previous hearings in which representatives from Facebook or Google have been present it hasn’t been unusual for questions to not focus on the investigation, but to also be on other topics of interest. In addition to questions on the competition practices, I expect there to be questioned on censorship, with the most recent well-known instance being the removal of a group that called themselves “American Frontline Doctors.” The group held a live stream on Monday that made claims of a cure for COVID-19, stating that masks offer no question, and made many other statements that contradict the advice of health organizations. The video was removed by Facebook, Twitter, and YouTube in addition to SquareSpace deciding to terminate their hosting agreement for the group’s site.

Previous hearings from the sub-committee are also available for viewing.

  1. Free and Diverse Press (June 11, 2019)
  2. H.R. 3942, Preventing the Sale of E-Cigarettes (June 11, 2019)
  3. Competition in Labor Markets (29 October, 2019)
  4. The perspective of the Antitrust Agencies (2019 November 13)
  5. Competitors in the Digital Economy (Jan 17, 2020)
  6. Online Platforms and Market Power (July 29, 2020)

Windows Terminal Preview


I’ve started using the Windows Terminal preview and wish I had started sooner. Some of the functionality that is provides while simple is useful and gives a productivity boost. I’m bringing attention to the Windows Terminal because I find it so useful. The first question to answer is “What is it?”

From the name alone you might think that the Windows Terminal is yet another command line in the same ranks as the command prompt and PowerShell. This isn’t what it is. It is a new console host. The console host (c:\Windows\System32\conhost.exe)¬† may be something to which there’s not a lot of awareness, but it is a behind-the-scenes component that host console programs. When you start the command prompt it runs within the console host.


The Windows Terminal is an alternative console host. It is a program for managing various console environments in a single window with tabs.¬† Upon installation it is pre-configured for the Command Prompt, Powershell, and the Azure Cloud Shell. The availability of these items in a tabbed window alone is sufficient for me to find it useful. It isn’t limited to these programs though. The Windows Terminal is configurable to host other console programs through editing a JSON configuration file. There are some devices that I regularly connect to using SSH.¬† I’ve extended my configuration to have entries for these specific devices.¬† I had been previously using PUTTY for this but I find that with the Windows Terminal the process of opening a new tab into a device is easier.¬† The other connections are available in two clicks; one on a down-arrow on the tab, and another on the terminal to be opened.


Figuring out how to add items to the Windows Terminal is easy even without looking at the documentation. The Settings menu item in the drop down opens the configuration file in which you can see the entries for the PowerShell, Command Propmt, and Azure Cloud Shell.¬† If you wanted to add a new terminal you can copy one of the entries and makes changes.¬† There are a lot of other settings that haven’t been defined here. The fuller range of possible settings are published in Microsoft’s Github account.

A feature I find especially useful is the ability to set the a background image to the terminal The background image could be an animated GIF (I won’t do that, it is too distracting).¬† I have set the background images to something relevant to the terminal so that at a glance I can tell what terminal I’m looking at. For example, when I had a connection to one of my NVIDIA devices and a Raspberry Pi my windows look like the following.


I’ve made my images intentionally dark, but they can be within what ever color range is of your choosing. Color schemes for the text itself are also definable.¬† Custom images for icons and terminal backgrounds must be placed in one of two locations.

URI Scheme Location
ms-appdata:///Local/ %localappdata%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\
ms-appdata:///Roaming/ %localappdata%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\RoamingState\

For the entry for one of my Raspberry Pi’s I’ve got the following configuration using the Roaming URI scheme to refer to a background image.


    "guid": "{89CF3D23-06EA-4B1E-B42D-FC61239443ED}",
    "closeOnExit": true,
    "backgroundImage": "ms-appdata:///roaming/pi.png",
    "backgroundImageOpacity": 0.75,
    "backgroundImageStrechMode": "fill",
    "name": "SSH Raspberry Pi 3 (Sense Hat)",
    "commandline": "ssh -l pi",
    "hidden": false

As with many keyboard driven interfaces there are hotkeys that you can press to perform actions. Some hotkeys are predefined, but you can define your own or change the predefined commands through the same JSON file in which the terminal entries exists.

In many programs pressing shift+enter will change a program to full screen model. I wanted to have the same behaviour in Windows Terminal and made an entry in the keybindings section for this.

{"command": "togleFullScreen", "keys": "shift+enter"}

The Windows Terminal also supports the full range of Unicode characters.  To take advantage of this the shell that you are using also needs to have support for it to. Many already do but had no way of properly displaying the characters.


The Windows Terminal is available in the Microsoft Store for free or from Github.

twitterLogofacebookLogo youtubeLogo


Windows Powershell Cookbook

Going Text:Mastering the Power of the Command Line

Sending Text Message from .NET


I met with some others in Singapore for a project deployment, and one of the other people there wanted a snippet of information sent to him. He wanted it sent to his phone. He asked what the most popular messaging application is in the USA. While Facebook Messenger is the most popular the messaging landscape in the USA is fractured. One’s preferred messenger is going to depend on their preferences and social circle (Telegram is my favourite). Because of this SMS remains the most reliable way of sending short messages to someone. When I am traveling around the USA or in some environments (the subway, inside certain buildings) I use SMS because data service becomes incredibly spotty.

I am making an ASP.NET application for which I want to be able to send notifications to a phone with no application installation necessary.  I will be using SMS as my message transport of choice. How does an application do this? There are a few solutions. One is to subscribe to an SMS Gateway Service and use their API.  I found several companies that provide these services. But many of them do not have price information openly available; speaking to a sales agent is necessary to get the price. A few that I encountered did share their prices. I share what I found here. Note that prices are subject to change and the older this post is the more likely the pricing information is stale.

SMS Gateway Services


Vonage offers SMS services starting at 0.0068 USD per message sent and and 0.0062 per message received. They also rent out virtual phone numbers at 0.98 USD per month. Verizon and US Cellular charge an additional fee for sending messages via long codes (0.0025 USD for Vzw and 0.0050 USD for US Cellular).  If you would like to try it out a trial level subscription is available for free. Vonage provides SDKs for several languages. They also have full code samples for each one of these languages.

  • Ruby
  • PHP
  • Python
  • .Net
  • NodeJS
  • Java
  • CLI


ClickSend offers a REST API for accessing their services. Like Vonage they also offer SDKs for several environments and code samples on how to perform various actions. You will find code samples and/or SDKs for

  • cURL
  • PHP
  • C#
  • Java
  • Node.JS
  • Ruby
  • Python
  • Perl
  • Go
  • Objective-C
  • Swift

Pricing is structured much differently. There are pricing tiers dependent on how many messages are sent. The pricing tiers look like the following.

  • 0.0214 USD/message up to 2,000 messages
  • 0.0153 USD/message for more than 2,000 messages
  • 0.0104 USD/message for 10k messages or more
  • 0.0076 USD/message for 100k messages or more
  • Unspecified pricing for more than 200k messages

A dedicated number is purchasable for 3.06 USD/month. Short codes cost 886.82 USD/month.

D7 Networks

D7 Networks pricing is  0.005 USD/month for sending SMS for one-way communication. For 2-way communication the fee is 2.00 USD/month + 0.012 USD/message for outbound messages and 0.00 USD for incoming messages.  While there is no SDK there is a REST API (which is easy enough to consume from most development environments).


Provided someone can identify their service provider e-mail is an option. An advantage of using Email to send an SMS is that it is free. A downside is that when registering with your service the recipient must know the service provider. While I do not think that is a general problem there may be cases where someone does not know; such as when their phone is part of a family plan and someone else handles the service. Another possible issue is a person properly registers but later changes their service provider and does not update it within your service.

Why does a user need to know their service provider for this to work? The USA carriers have domains that that are used for sending e-SMS messages via e-mail. Appending this domain to the end of someone’s phone number results in the e-mail address that is routed to their phones.

  • AT&T –
  • Boost Mobile –
  • Cricket Wireless –
  • Google Project Fi –
  • Republic Wireless –
  • Sprint –
  • Straight Talk –
  • T-Mobile –
  • Ting –
  • Tracfone –
  • US Cellular –
  • Verizon –
  • Virgin Mobile –

Sending messages in .Net is just a matter of using the SmtpClient class. The exact configuration that you need will be dependent on your mail service. For my mail service I have pre-configured the credentials in the computer’s credential store so that the information does not need to be stored in my application’s configuration.

SmtpClient mailClient = new SmtpClient("")
     Credentials = CredentialCache.DefaultNetworkCredentials
var message = new MailMessage(
   "", //blank subject
   "test body"
twitterLogofacebookLogo   youtubeLogo posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.


c# 8

Introduction to SASS

SASS, or Syntactically Awesome Style Sheets, are a style sheet language that compile to CSS. I have mentioned languages that compile to another language before. TypeScript is an example. If you have used a system that compiles one language to another you may be able to guess why someone might want to make a new style sheet language that compiles to another.

SASS retains some amount of familiarity with CSS. This alternative syntax is more expressive; a developer can write less code to express the same design as the equivalent CSS. It also is not necessary to wait on browsers to have some feature to start using SASS; the layer of separation provided by the compiler allows SASS to have less dependencies on a browser supporting a set of features to be useful. In this first of a two part post I wanted o introduce some of the elements of SASS. Here I demonstrate variables, nesting, and replacement. In the second post I will focus on control structures and functions.

There are several GUI and command line solutions for compiling SASS. My preference is for the command line tool. The command line tool is easy enough to use both directly and to integrate into other build tools.  Installation using the Node Package Manager works on Windows, Linux, and macOS (though for me it does not work with the Windows Power Shell while it works fine in the command terminal).

npm install sass -g

If you would like to check if a system has sass installed and the version number type the following.

sass --version

Much like TypeScript, think of SASS as a super set of CSS. This is not 100% the case, but it is a good starting point for understanding. SASS styles might be distributed among several files, but when compiled the output will be in a single files.  SASS files will typically have the extension *.scss.  As an initial test I have created two files in a folder. One is named first.scss and the other is named second.scss. The following is the contents of first.sass:

@import 'second';
first {
font-family: Arial;

And of second.sass:

font-family: Arial;

Since first.sass is my main file of this set to compile these files I am selecting first.sass as the input to the pre-processor. When the pre-processor encounters the @import keyword it will replace that line with the contents of the files whose name is specified there. Note that I did not need to include the extension to the file name here.  To compile these files I use the following command:

sass first.sass output.css

After running the command there is a new file named output.css.

second {
font-family: Arial;

first {
font-family: Arial;

Chances are that you are not going to want to issue a command at the command prompt every time you make a change to one of the SASS files.¬† To avoid this you can add the parameter –watch to the command line and allow it to continue to run. Every time you modify a SASS file the compiler will regenerate output.css.

sass --watch first.scss output.css


One of the first constructs that you will use in SASS is variables. Variables are recognizable from the $ prefix that they have. A variable can hold a Boolean, color, numeric, or string values. It is easy to undervalue variables at first; CSS already provide variables. Why are SASS variables needed? SASS variables are usable in places and ways in which CSS variables are not.  Some of the ways that variables can be used to create a style sheet will come up in some of the following sections. Let us look at a typical scenario first.

$primaryColor : #FF0000;
$secondaryColor: #FFFFD0;
This creates two variables that hold colors. These colors can be used within the SASS  in place of an actual color code.
body {
   background-color: $secondaryColor;

.container > div {
   background-color: $primaryColor;

Variables have a scope. If a variable is declared outside of brackets it is globally accessible. If it is declared within the SASS block enveloped by brackets it is only visible to the SASS code within that block. In the following the second instance of $borderColor will cause an error from a variable not being defined. The variable of the same name declared in the first block is not within scope.

body {
   $borderColor: #0000FF;
   background-color: $secondaryColor;

.container > div {
   background-color: $primaryColor;
   border: 1px solid $borderColor;

Default Values for Variables

You may make a SASS and want to allow a user to customize it through defining values for some variables. But you might not want to obligate the user to define values for all of the variables that your SASS uses. For this scenario there are default values.  To assign a variable a default values append the assignment with !default.
$primaryColor: #FF0000 !default;
The assignment occurs only if the variable is undefined or has a null values.  If there are any SASS definitions that use the variable before it is assigned a values other than its default those blocks that occur before the new assignment will not have the new values. The default would need to be overridden before it was used.  This could mean defining a variable before including the library that will be used. But there is another way that I think is cleaner.
With the @use directive a SASS library can be included and the variables to be assigned new values can be specified using the keyword “with” and a list of the variable assignments.
@use  'second' with (
   $primaryColor: #FF00FF

Nesting Selectors

The ability to nest selectors is a feature that in my opinion allows for much neater style sheets. It is common within CSS to have selectors based on some parent/child relationship. Here is a simple example.

.demoView {

.demoView .left {
   background-color: red;

.demoView .middle {
   background-color: green;

.demoView .right {
   background-color: blue;
While these style selectors are all related they are each in their own  own declaration independent of each other. Under SASS they could be grouped together. Each selector is referring to elements that are children of an element of the demoView class. A single demoView declaration is made in my SASS file. For selectors that are targeting children of demoView within SASS they are declared within  the demoView class selector.
.demoView {

   .left {
      background-color: red;
   .middle {
      background-color: green;
   .right {
      background-color: blue;
I personally find this pleasing since the SASS’s layout is now closer to the arrangement of the elements within the HTML.

Parent Selector

The ampersand (&) character is used as a parent selector operator.  The & is replaced with what ever the parent selector is.
a {
   text-decoration: none;;
   &:hover {
Here the potential use of the operator might not be entirely obvious. Think of it as performing a string replacement.
.icon {
   &-left {
   &-right {
This expands to the following.
.icon {
   &-left {
   &-right {
Not that this is the only way that a string substitution can occur. There is also the string interpolation operation.

String Interpolation

String interpolation substitutes the values of a variable into a string. String interpolation operations use #{}  with a variable name inserted between the brackets. String interpolation can be used in a selector, attribute name, or values.
item-#{$index} {
expands to
item-4 {
color: red;
The potential for this operation becomes more powerful once used within other constructs such as loops. Control structures will be the topic of the second half of this post, but I will show a brief example here.
@for $i from 1 to 4 {
   item-#{$i} {
      animation-delay: #{$i}s;
item-1 {
   animation-delay: 1s;

item-2 {
   animation-delay: 2s;

item-3 {
   animation-delay: 3s;

Placeholder Selectors and @extend

Placeholder selectors look like class selectors. But they are proceeded with a % instead of a period. The first thing to note about placeholder selectors is that they do not generate any CSS output. Any selector that contains a place holder selector will not be rendered to the CSS output. At first, placeholders appear useless. The placeholder selectors are made to be used with @extend. Use @extend to import the attributes from a place holder selector into another selector.
%blockElement {

.redBlock {
   @extend %blockElement;
   background-color: red;

.greenBlock {
   @extend %blockElement;
   background-color: green;
This is the CSS produced by the above.
.greenBlock, .redBlock {
display: block;
width: 100px;
height: 100px;

.redBlock {
background-color: red;

.greenBlock {
background-color: green;
Nothing in what I have shown thus far is complex and I think it is easy to to understand the individual elements. But for a deeper understanding I think it best to start putting this information to use. Exercise one’s understanding through some simple projects to strengthen that understanding.¬† When the next portion of this post is published¬† will dive straight into control structures and functions. With those the potential to generate complex CSS from much simpler SASS increases significantly.
Until the next entry if you would like to see my other posts on HTMLrelated topics click here.
twitterLogofacebookLogo  youtubeLogo

Mastering SASS

SASS and Compass

Apple, Alphabet, Amazon, and Facebook Called to Congress

Monopoly logo

Some of the largest technology companies in the USA have yet again been called to testify at the House of Representatives to testify. They have been called many times before. This time it is on competition. Some have alleged that each of these companies has done something to hinder competition and they are being called to speak on it. In a letter written to these companies the House has asked that the CEOs of these companies be the ones to testify. They are also asking the companies to produce documents that were generated in response to competition. If the companies do not produce documentation they may be subpoenaed and obligated to produce it anyway.

For Apple the only way to publish an application is through the Apple App Store. For applications published thay way Apple earns a portion of the sales and subscriptions. Apps sold through the App store cannot advertise paying for services through means other than the App store.

Alphabet (the parent company of Google) has been accused of anticompetitive behaviours along several fronts. This includes giving preference to Alphabet provided serviced in Google searches and having an extensive advertising vertical.

Amazon is a bit unique. Previous anticompetitive cases have focused on consumer welfare. But Amazon’s practices haven’t met past criteria for poor consumer welfare. Amazon has access to lots of sells data and the computational and AI capabilities for profitably using that information and under pricing those that sell through their service.

Facebook has been accused of cutting developers off from their services to serve their own purposes. They have also purchased other services that might have competed with them otherwise (ex:Instagram). Some competitors have described Facebook as an unlawful monopoly.

Whether or not these companies engage in anticompetitive behaviour is a topic of debate. This hearing is part of an ongoing investigation into competition in technology. At the same time the EU is launching an anti-competitive investigation on Apple’s App Store and on Apple Pay. The investigation is based on a complaint from Spotify from last year and a complaint from an unnamed ebook/audio-book distributor. Their complaints are on the fee that must be payed to Apple for services purchased through the user’s iOS device and the prohibitions on communicating to users how they can upgrade their services through other means. For Apple Pay the investigation is on that being the only contactless payment solution that can be deployed to the iPhone. Especially at a time when there is increased interest in contacless transactions in the wake of COVID-19.

Instagram LogoLinked In

Case Sensitive File System on Windows


As of Windows 10 build 1803 case sensitive files names can be enabled on Windows. This is a feature that I have found useful while working in an environment where some developers run macOS and others run Windows. Occasionally a macOS developer would encounter an error about a missing file that the Windows developers didn’t encounter. The problem was usually because of inconsistent casing being used in a file name and some reference to the file in code.¬† By enabling the case sensitive file system the Windows developers are able to better check when their casing is inconsistent.

The feature is enabled on a folder and its children. It isn’t something that you would want to try to enable system wide. I use this feature on project folders.

To enable the case sensitive file system open an administrative command prompt. Then use the following command.

fsutil.exe file SetCaseSensitiveInfo c:\PathTo\Target\Folder enable

After the command runs you can test it out by creating a few files in the folder that have the same name with different casing. If you ever want to turn off the case sensitive file system the command to do this is similar.

fsutil.exe file SetCaseSensitiveInfo c:\PathTo\Target\Folder disable


Taking a Look at the Azure Kinect DK

My interest in the Azure Kinect DK has increased since I was able to get my hands on one of the devices. Because of the Azure branding, I expected it to only be a streaming device for getting data into the Azure Cloud for processing. My expectation was wrong. While the device is supported by Azure branded services, it is a fully implemented device with local functionality of its own. In this post I will only give a brief introduction to the Azure Kinect DK. In the future, I will go deeper into the code.

The Azure Kinect DK comes with the camera itself, a USB-C to USB-A cable, and an external power supply. When connected to a computer that supports USB-C Power Delivery, only the USB-C cable is needed. The SDK for the Azure Kinect DK is available from Microsoft for free.

It works on Ubuntu Linux 18.04 in addition to working on Windows! To install the tools on Linux you can do the following.

sudo apt install k4a-tools

Physical Build

The Azure Kinect DK has a solid feel to the build. The body of the Kinect itself is an anodized aluminum. The back end of the Kinect is covered with a plastic sleeve that slides off to show additional mounting options. In addition to the standard quarter-inch screw mount that is commonly found on cameras, removing the sleeve on the underside of the the Azure Kinect DK exposes screw mounts on the side. The distance between the screw holes and the screw size is labeled. (The spacing of these holes can also be found on the Azure Kinect specifications page)


Field of View

There are three cameras on the device. An item being within the field of view (FoV) of one of the cameras does not indicate that it is within the FoV of all three of them. There are two depth sensing cameras: one with a narrow FoV and another with a wide FoV. There is also a color (RGB) camera. The following diagram is from Microsoft’s site showing the three fields of view of the cameras.

Camera FOV

I thought that the following image was especially useful in showing the differences in the FoV. If the unit were facing a wall straight on from 2,000 meters this is the overlapping area of what each camera would be able to see. Note that the RGB camera can work in two aspect ratios 16:9 and 4:3.

Camera FOV Front


The Kinect has a number of sensors within it. The most obvious ones are in the cameras (RGB camera and depth camera). There is also a microphone array on the top of the Kinect. It is composed of 7 microphones. The computer sees it as a regular USB audio device.

Another sensor, and one that I did not expect, is the motion sensor. There is a 6-degrees of freedom sensor within it that samples at a rate of 1.6 KHz, though it only reports updates to the host at a rate of 208 Hz. The IMU is based on the LDM6DSMUS. The sensor is mounted within the unit, close to but not quite to the center of the unit.


Recording Data

Like the previous versions of the Kinect, with this version you can record a data stream from it to be played back later. Recording is done from a command line and allows the frame rate to be specified. The only thing the command line utility will not record is the signals to the microphones. The resulting file is an MKV file where the sensor data is within some of the other streams. I was successful at viewing the RGB stream in some third party video players. The Azure Kinect DK contains a utility that can be used to open these files and play them back.

Body Tracking

For body tracking a developer’s program grabs a sample from the camera and passes it through the Azure Kinect Tracker. The Tracker is a software component that can run either on the CPU or take advantage of the computational capabilities of the system’s GPU. After trying it out myself, I strongly encourage using the GPU. I am currently using a MacBook running Windows. With CPU based body tracking I wasn’t seeing the results that I was looking for. When I connected a NVIDIA GTX 1080 in an eGPU case I started to get body tracking rates of 20-25 FPS with two people in the scene.

GTX 1080 within

Capturing Data

I would describe the Azure Kinect DK as a C++ first kit. Most of the documentation that I have found on it is in C++. Microsoft did release a .NET SDK for the device also. But I have often had to refer to the C++ documentation to get information that I need. The .NET SDK is close enough to the C++ APIs for the C++ documentation to be sufficiently applicable. A lot of the APIs were intuitive.

The SDK is 64-bit only. You may need to take into consideration when using it with other software components that may only be available in 32-bit. I have found it is easiest to add the needed software components to a project using the NuGet package manager. To only grab information from the Azure Kinect’s sensors the only package needed is Microsoft.Azure.Kinect.Sensor ( ). If you plan on using the body tracking SDK then use the package Microsoft.Azure.Kinect.BodyTracking.Dependencies.cuDNN. There are other packages that are needed, but by adding this one the other dependencies will also be selected.

A system could be connected to multiple Azure Kinects. To know the number of available Kinects on a system, use the static method Device.GetInstalledCount(). To open a device, use the static method Device.Open(uint index). An open device does not immediately start generating data. To start retrieving data the device must be started with a DeviceConfiguration. The DeviceConfiguration sets the FPS and pixel formats for the camera.

DeviceConfiguration dc = new DeviceConfiguration();
dc.CameraFPS = FPS.FPS30;
dc.ColorResolution = ColorResolution.R1080p;
dc.ColorFormat = ImageFormat.ColorBGRA32;
dc.DepthMode = DepthMode.NFOV_2x2Binned;

With the device configuration a device is opened through the static method Device.Open(DeviceConfiguration). Calling StartCameras(DeviceConfiguration) puts the device in a state for retrieving data. Once the camera is started the device’s IMU can also be started to retrieve orientation data ( use StartImu() ).

The color image, depth image, and IR image are retrieved through a single function call. The GetCapture() method on the opened devices returns a Capture object that contains all of these images along with the device’s temperature. The device’s GetImuSample() returns information from the devices accelerometer and gyrometer. The images are returned in a structure that provides an array of bytes (for the image data) and other values that describe the organization of the image bytes.

Tracking People

To retrieve the information on the position of people within a capture a Tracker is necessary. A capture is added to the tracker’s queue and the queue outputs the positions of people within the scene. For the creation of a tracker a device’s calibration data and a tracker configuration are needed. A TrackerConfiguration object specifies whether to use the GPU or CPU for for processing. When using the GPU a specific GPU can be selected through the tracker configuration. The TrackerConfiguration also holds the orientation of the Kinect. In addition to the default positioning (the position it would be in if it were mounted on top of a tripod) the Kinect could be rotated to portrait mode or be positioned upside down.

TrackerConfiguration tc = new TrackerConfiguration();
tc.ProcessingMode = TrackerProcessingMode.Gpu;
tc.SensorOrientation = SensorOrientation.Default;
Tracker tracker = Tracker.Create(dev.GetCalibration(), tc);

Add a capture from a device into the tracker. Calling the PopResult() method will return the result (if it is ready). If the results are not ready within some length of time this method will throw an exception. The method accepts a TimeSpan object and a boolean value. The TimeSpan sets a new timeout value for waiting. The boolean, if set to true, will cause the method to throw an exception if a result is not available within the timeout period. If this value is set to false, then a null value is returned when a result is not ready, instead of an exception being thrown.


That provides enough information to collection information from an Azure. But once collected what can be done with it? In the next post on the Azure Kinect DK I will demonstrate how to use it to enhance user experiences and explore other modes of interaction that are made available through it.

Get the Azure Kinect DK on Amazon




Azure for Developers

Microsoft Azure Fundamentals

8 Gig Pi and New Jetson Board

There have been a couple of SBC updates in the past few weeks that I thought were noteworthy.


The first is that there is now a 64-bit version of the Raspberry Pi operating system available. Previously if you wanted to run a 64-bit OS on the Pi your primary option was Ubuntu. Raspbian was 32-bit only. That’s not the case any more. The OS has also been rebranded as “Raspberry Pi OS.” Among other things with the updated OS a process can take advantage of more memory.  Speaking of more memory, there is now also an 8 gig version of the Raspberry Pi 4 available for 75.00 USD.

Jetson Xavier NX

Another family of single board computers is seeing an update. The Jetson family of SBCs has a new edition in the form of the Jetson Xavier NX.  At first glance the Xavier NX is easily confused with the Jetson Nano. Unlike the Nano the Xavier NX comes with a WiFi card and a plastic base around the carrier board that houses the antenna. The carrier board is one of the variants that supports 2 Raspberry Pi camera connectors. The underside of the board now has a M.2 Key E connector. While it has a similar formfactor as the Jetson Nano a quick glance at the specs show that it is much more powerful.

FeatureNanoXavier NX
Core Count46
CUDA Core Count128384
Memory4 Gigs8 Gigs

The Jetson Xavier NX is available now for about 400 USD from several suppliers.

Run .NET Core on the Raspberry Pi

Post on the NVIDIA Jetson

Instagram LogoLinked In

Posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.

Jetson Xavier NX

Raspberry Pi 4

Saving your Automotive data from with NodeJS

One of the less glamorous experiences that has come with Consumer IoT products is a parade of items that cease to work when the company that made them shuts down. The economic down turn of 2020 has seen it’s share of products that have experienced this. In a few days the automotive adapters from will be on the list of causalities. provided a device that connect to a car through the ODB-II port and would relay information about a vehicle back to the owner that they could view through an application or through the web portal.  Through these views someone could see where their car is, read any engine trouble code, view the paths the car has traveled, and view information about hard breaks, hard accelerations, and other car data.

I have three of these adapters and have data from tracking the vehicles for the past 5 years. I would rather keep my information. Looking on’s page about the shutdown there is a statement about exporting one’s data.

To download and export your driving data, you’ll need to log in to the Automatic Web Dashboard on a desktop or laptop computer at Click on the ‚ÄúExport‚ÄĚ button in the lower right-hand corner of the page.
Although the number of trips varies between each user, the web app may freeze when selecting ‚ÄúExport all trips‚ÄĚ if you are exporting a large amount of driving data. We recommend requesting your trip history in quarterly increments, but if you drive in excess of 1,500 trips per year, please request a monthly export.”

I tried this out myself and found it to be problematic. Indeed, after several years of driving across multiple vehicles the interface would freeze on me. I could only actually export a month of data at a time.¬† Rather than download my data one month at a time across 60 months it was easier to just write code to download my data. Looking through the API documentation there were three items of data that I wanted to download. I’ll be using NodeJS to access and save my data.

To access the data it’s necessary to have an API key. Normally there would be the process of setting up OAUTH authentication to acquire this key. But this code is essentially throw away code; after Automatic completes it’s shutdown it won’t be good for much. So instead I’m going to get a key directly from the developer panel on I’ve got more than one automatic account. It was necessary to do this for each on of the accounts to retrieve the keys.

On select “Create new App.”¬† Fill out some description for the app. After the entry is saved select “Test Token for your Account.”


You’ll be presented with a key. Hold onto this. I placed my keys in a comma delimited string and saved it to an environment variable named “AutomaticTokens.”¬† It was an easy location from which to retrieve them where I won’t have to worry about accidentally sharing them while sharing my code.¬† In the code I will retrieve these keys, break them up, and process them one at a time.¬†

var AutomaticTokensString = process.env.AutomaticTokens;
const AutomaticTokenList = AutomaticTokensString.split(',');
For calling’s REST based API most of the calls look the same differing only in the URL. I’ve made a method to make calls, accumulate the responses, and pass them back.
function AutomaticAPI(path) {
    return new Promise(function(resolve,reject) {
        var options = {
            host: '',
            path: path,
            method: 'GET',
            headers: {Authorization:`Bearer ${AuthorizationToken}`}
        var req = https.request(options,function(res) {
            let data = ''
            res.on('data', function (chunk) {
                data += chunk;
            res.on('end',function() {
        req.on('error', function(e) {
            console.log('problem with request: ' + e.message);
This greatly simplifies the implementations of the rest of the calls.
Now that I have the keys and something in place to simply the calls the first piece of information to retrieve is a list of vehicles in the account. This information is the root of of the other information that I wanted to save.
function listVehicles() {
    return new Promise((resolve,reject)=>{
        .then(function(d) {

Let’s take a look at one of the responses from this call.

     _metadata: { count: 1, next: null, previous: null },
     results: [
               active_dtcs: [],
               battery_voltage: 12.511,
                created_at: '2017-01-28T21:49:24.269000Z',
               display_name: null,
               fuel_grade: 'regular',
               fuel_level_percent: -0.39215687,
               id: 'C_xxxxxxxxxxxxxxxxx',
               make: 'Honda',
               model: 'Accord Sdn',
               submodel: 'EX w/Leather',
               updated_at: '2018-07-24T19:57:54.127000Z',
               url: '',
               year: 2001

From the response I need to id field to retrieve the other information. While this response doesn’t change any ground breaking information I’m persisting it to disc so that I can map the other data that I’m saving to a real car.

The next thing I grab is the MIL. This contains the last set of engine trouble codes with date stamps.

function getMil(vehicleID, limit,) {
    return new Promise((resolve,reject)=>{
        var url = `/vehicle/${vehicleID}/mil/`;

Here is a sample response.

   "_metadata": {
      "count": 3,
      "next": null,
      "previous": null
   "results": [
         "code": "P0780",
         "on": false,
         "created_at": "2019-07-09T20:19:04Z",
         "description": "Shift Error"
         "code": "P0300",
         "on": false,
         "created_at": "2018-02-24T16:05:02Z",
         "description": "Random/Multiple Cylinder Misfire Detected"
         "code": "P0306",
         "on": false,
         "created_at": "2018-02-24T16:05:02Z",
         "description": "Cylinder 6 Misfire Detected"

The last, and most important piece of information that I want is the trip data. The trip data contains a start address, end address, and the path traveled.¬† Information about hard stopping and hard acceleration and many other items of data is stored within trips. For the REST API a start time and end time are arguments to the request for trip information. The API is supposed to support paging when there are a lot of trips to return. Some number of trips are returned from a request along with a URL that contains the next page of data. When I’ve requested the second page I get an error response back. Given the short amount of time until the service shuts down it doesn’t feel like the time to report that dependency to the staff at Instead I’m requesting the travel information for 7 to 9 days at a time. The results come back in an array. I’m writing each trip to it’s own file.

To more easily navigate to a trip I’ve separated them out in the file system by date. The folder structure follows this pattern.


The information within these files is the JSON portion of the response for that one trip without any modification.¬† The meaning of the information in most of the fields of a response are easy to intuitively understand without further documentation. The field names and the data values are descriptive. The one exception is the field “path.” While the purpose of this field is known (to express the path driven) the data value is not intuitive. The data value is an encoded poly line. But documentation on how this is encoded can be found in the Google Maps documentation ( ).

Now that I’ve got my data saved I may implement my own solution for continuing to have access to this functionality. At first glance I see some products that appear to offer similar services. But the lack of an API for accessing the data makes them a no-go to me. I’m instead am learning towards making a solution with an ELM327 ODB-II adapter, something I’ve used before.

Download Code:

twitterLogofacebookLogoyoutubeLogoInstagram Logo

Linked In




ODB II Bluetooth Adapter

OSB II Scanner