Review: Fortebit Polaris 3G Kit+
A question of software
The Polaris GPS tracker is different from most other trackers; in this case that’s a good thing from a developer and customer’s perspective. It is an open platform, something that is rarely the case with GPS trackers. The tracker comes preloaded with firmware to perform basic functions for tracking vehicles; this is of course the minimum requirement for such a device and something that other competing systems also provide. The big difference with the Fortebit Polaris tracker is that you can also write your own software and not only C / C ++ is available as programming language. Each device is delivered with the Python-based ZERYNTH middleware for IoT and an integrated license for the Python environment it contains. ZERYNTH Studio, which can be downloaded from the manufacturer, is required to carry out development. Even if you don't want to get started with Python, you should do this, as the integrated license for the Python environment on the MCU would otherwise be lost if a Python program was not successfully transferred at least once for the license to be registered on the local computer. Something that should be pointed out is that it is necessary to register an account with the manufacturer in order to be able to use the ZERYNTH Studio.The ZERYNTH Studio uses a fairly basic text editor; if you want a pure editor for writing source text, you are better off using your own favourite or installing an alternative (free) software package. Amongst other things, the environment supports Visual Code. The Python environment license can and should be registered before you go any further. Once this has been done we can begin with the first test of the GPS tracker. The device firmware can only exchange data with the Fortebit portal, which in turn requires an account. This account usually incurs a charge but is free for the first 30 days of use. Anyone wanting to monitor a fleet of vehicles or other things will have their own requirements for data processing and preparation. Therefore, the portal is not taken into account here, because it is primarily about the hardware and not establishing a fleet telematics portal.
From this point on, you have to work yourself to get the demo application to exchange the data with your own system of choice. Even those wanting to operate a portal for tracking vehicle data themselves cannot avoid this step. This is something that still leaves room for improvement over the otherwise good first impression. If you don't want to work with Python, you can of course provide the GPS tracker with software via the Arduino environment. The necessary software and board packages can be found on the ForteBit GitHub account and integrated into the Arduino IDE using the Board Manager facility.
The Python example was redesigned for a quick test run (N.B. this is just a quick demo version, not suitable for a production application). Despite this the demo shows how the hardware can be connected to an MQTT broker of your choice. With a few lines of Python code the necessary changes are implemented and quickly transferred to the hardware. The GPS data is then routed to an MQTT broker of your choice.
To sum up
The open hardware approach of the GPS tracker and the flexibility in the selection of the development environment and programming language make the Fortebit Polaris 3G + Kit a very interesting platform to develop GPS tracker applications. Its key feature is its open source approach with the ability to implement your own custom functions. Documentation and support including some examples using Python and the Arduino environment are sure to be expanded upon as popularity of the unit picks up momentum. It is hoped the manufacturer will stay on board to help promote the platform and provide support to developers. The main.py listing (modified) using the Polaris 3G+ using its own MQTT broker is given below:# POLARIS_FORTEBIT
# Created at 2019-07-26 11:34:26.282569
# modified by someone(tm) 06-08-2020 for generic MQTT ( unsecured ) transport
# to use test.mosquitto.org as mqtt broker
# not for production use at all !
from mqtt import mqtt
from fortebit.polaris import polaris
from fortebit.polaris import modem
from fortebit.polaris import gnss
import vm
import sfw
vm.set_option(vm.VM_OPT_RESET_ON_EXCEPTION, 1)
vm.set_option(vm.VM_OPT_TRACE_ON_EXCEPTION, 1)
vm.set_option(vm.VM_OPT_RESET_ON_HARDFAULT, 1)
vm.set_option(vm.VM_OPT_TRACE_ON_HARDFAULT, 1)
import streams
s = streams.serial()
import mcu
import timestamp
import timers
import ssl
import requests
import threading
from wireless import gsm
import utils
sleep(1000)
# CONFIG
poll_time = 100 # poll inputs at twice the specified period in ms
gps_period = 10000 # gps lat,lon and speed telemetry period in ms
update_period = 6 * gps_period # other telemetry data period in ms
no_ignition_period = 300000 # no ignition telemetry data period in ms
fw_version = "1.11"
# POLARIS INIT
try:
print("Polaris default app")
polaris.init()
print("MCU UID:", [hex(b) for b in mcu.uid()])
print("VM info:", vm.info())
print("FW version:", fw_version)
print("Watchdog was triggered:", sfw.watchdog_triggered())
polaris.ledRedOn()
polaris.ledGreenOff()
except Exception as e:
print("Failed polaris init with", e)
sleep(500)
mcu.reset()
# INIT HW
try:
print("Initializing Modem...")
modem = modem.init()
print("Initializing GNSS...")
gnss = gnss.init()
# verify preconditions and start utility thread
utils.start()
print("Starting Accelerometer...")
import accel
accel.start()
print("Starting GNSS...")
gnss.start()
gnss.set_rate(2000)
print("Starting Modem...")
modem.startup()
# enable modem/gnss utilities
utils.modem = modem
utils.gnss = gnss
sfw.watchdog(0, 30000)
sfw.kick()
if utils.check_terminal(s):
utils.do_terminal(s)
minfo = gsm.mobile_info()
print("Modem:", minfo)
# enable SMS checking
utils.check_sms = True
except Exception as e:
print("Failed init hw with", e)
sleep(500)
mcu.reset()
# GATHERING SETTINGS
name = None
apn = None
email = None
try:
print("Read settings...")
settings = utils.readSettings()
sfw.kick()
if "apn" in settings:
apn = settings["apn"]
print("APN:", apn)
if "email" in settings:
email = settings["email"]
print("Email:", email)
if "name" in settings:
name = settings["name"]
print("Name:", name)
if apn is not None and not utils.validate_apn(apn):
print("Invalid APN!")
apn = None
if email is not None and not utils.validate_email(email):
print("Invalid email!")
email = None
if name is None:
name = "Polaris"
print("Saving name:", name)
settings["name"] = name
utils.saveSettings(settings)
if apn is None:
print("APN is not defined, can't connect to Internet!")
apn = utils.request_apn(s)
print("Saving email:", email)
print("Saving APN:", apn)
settings["apn"] = apn
utils.saveSettings(settings)
if email is None:
print("email is not defined, can't register to Cloud!")
email = utils.request_email(s)
settings["email"] = email
utils.saveSettings(settings)
except Exception as e:
print("Failed gathering settings with", e)
sleep(500)
mcu.reset()
# GSM ATTACH
try:
print("Waiting for network...",end='')
for _ in range(150):
sfw.kick()
ninfo = gsm.network_info()
if ninfo[6]:
break
sleep(1000)
if (_ % 10) == 9:
print('.',end='')
else:
raise TimeoutError
print("ok!")
print("Attached to network:", ninfo)
print("Activating data connection...")
for _ in range(3):
try:
gsm.attach(apn)
break
except Exception as e:
print("Retrying...", e)
try:
gsm.detach()
sleep(5000 * (_ + 1))
except:
pass
else:
raise TimeoutError
linfo = gsm.link_info()
print("Connection parameters:", linfo)
except Exception as e:
print("Network failure", e)
sleep(500)
mcu.reset()
# TELEMETRY LOOP
try:
accel.get_sigma() # reset accumulated value
sleep(500)
last_time = -(no_ignition_period + gps_period) # force sending data immediately
counter = 0
sos = -1
connected = True
ignition = None
sos = None
telemetry = {}
disconn_time = None
while True:
# allow other threads to run while waiting
sleep(poll_time*2)
sfw.kick()
now_time = timers.now()
if utils.check_terminal(s):
utils.do_terminal(s)
# read inputs
old_ign = ignition
ignition = polaris.getIgnitionStatus()
old_sos = sos
sos = polaris.getEmergencyStatus()
extra_send = False
# led waiting status
utils.status_led(False, ignition, connected)
if sos != old_sos:
telemetry['sos'] = sos
extra_send = True
if ignition != old_ign:
telemetry['ignition'] = ignition
extra_send = True
if not extra_send:
if ignition == 0:
# sleep as indicated by rate for no ignition
if now_time - last_time < no_ignition_period - poll_time:
continue
extra_send = True
else:
# sleep as indicated by rate
if now_time - last_time < gps_period - poll_time:
continue
ts = modem.rtc()
#print("MODEM RTC =", ts)
if counter % (update_period / gps_period) == 0 or extra_send:
telemetry['ignition'] = ignition
telemetry['sos'] = sos
if polaris.isBatteryBackup():
telemetry['charger'] = -1
else:
telemetry['battery'] = utils.decimal(3, polaris.readMainVoltage())
telemetry['charger'] = polaris.getChargerStatus()
telemetry['backup'] = utils.decimal(3, polaris.readBattVoltage())
telemetry['temperature'] = utils.decimal(2, accel.get_temperature())
telemetry['sigma'] = utils.decimal(3, accel.get_sigma())
pr = accel.get_pitchroll()
telemetry['pitch'] = utils.decimal(1, pr[0])
telemetry['roll'] = utils.decimal(1, pr[1])
if gnss.has_fix():
fix = gnss.fix()
# only transmit position when it's accurate
if fix[6] < 2.5:
telemetry['latitude'] = utils.decimal(6, fix[0])
telemetry['longitude'] = utils.decimal(6, fix[1])
telemetry['speed'] = utils.decimal(1, fix[3])
if counter % (update_period / gps_period) == 0 or extra_send:
telemetry['altitude'] = utils.decimal(1, fix[2])
telemetry['COG'] = utils.decimal(1, fix[4])
if counter % (update_period / gps_period) == 0 or extra_send:
telemetry['nsat'] = fix[5]
telemetry['HDOP'] = utils.decimal(2, fix[6])
# replace timestamp with GPS
ts = fix[9]
elif ts is not None and ts[0] < 2019:
ts = None
if ts is not None:
ts = str(timestamp.to_unix(ts)) + "000"
counter += 1
last_time = now_time
# led sending status
utils.status_led(True, ignition, connected)
telemetry['counter']=counter
telemetry['dev_ts']=ts
sfw.kick()
# set the mqtt id to "zerynth-mqtt"
client = mqtt.Client("zerynth-mqtt",True)
# and try to connect to "test.mosquitto.org"
for retry in range(10):
try:
client.connect("test.mosquitto.org", 60)
break
except Exception as e:
print("connecting...")
print("connected.")
print("Publishing:", telemetry)
client.publish("test", str(telemetry))
client.loop()
ok = False;
except Exception as e:
print("Failed telemetry loop", e)
sleep(500)
mcu.reset()
Read full article
Hide full article
Discussion (0 comments)