question

laurenceh avatar image

Where's my boat - answers rather than questions - GPS, Modbus, Hiawatha, HTML configuration

This is a set of answer rather than a question. The questions answered are:

1) How do I access Modbus registers using python?

2) How do I enable the Hiawatha server on Venus OS or GX device to run python scripts?

3) Where can I add my own HTML or script pages to be served by my GX device?

Last year we used a GPS GSM vehicle tracker device to keep track of the boat location while cruising but had no real programatic access to the location data. Using Venus OS on a Raspberry pi I have developed a method to access our location via web pages.

Enable Python scripts in the Venus OS Web server (Hiawatha)

Nano /etc/hiawatha/hiawatha.conf and uncomment the python script line


#CGIhandler = /usr/bin/perl:pl

#CGIhandler = /usr/bin/php-cgi:php

# enable by LH to run py as cgi scripts

CGIhandler = /usr/bin/python:py

#CGIhandler = /usr/bin/ruby:rb

#CGIhandler = /usr/bin/ssi-cgi:shtml

It is possible to modify hiawatha.conf to set up a new virtual server with specific access conditions to improve security. I have not covered these changes in this post but can look into it if anyone in interested.

Add pages to be served by the Hiawatha Server

Pages to be served can be added in the directory /var/www/venus

A new page page.html is then accessible on the GX local network as

http://<IP address>/page.html

If you want to access your pages from the internet you will need to reconfigure your routers firewall to direct incoming traffic from the internet to arrive at the IP address of the GX device. This is not necessary if you are just going to access the GX on the local network. If doing this for permanent use then it would be best to edit hiawatha.conf to set up a new virtual server as mentioned above, with out that your router may open access to your GX remote console without the security of going via the VRM.

Use python to access Modbus registers

Here is the python script I am using to read the latitude and longitude data from the GX Modbus.

#!/usr/bin/env python

#import pymodmus stuff

from pymodbus.constants import Defaults

from pymodbus.constants import Endian

from pymodbus.client.sync import ModbusTcpClient as ModbusClient

from pymodbus.payload import BinaryPayloadDecoder

Defaults.Timeout = 25

Defaults.Retries = 5

client = ModbusClient('localhost', port='502')

# need 4x16 bit registers so read argument is 4 - modbus is just like that

result = client.read_input_registers(2800, 4)

decoder = BinaryPayloadDecoder.fromRegisters(result.registers, endian=Endian.Big)

#This is written longahnd so that you can see what is happening

reg1=decoder.decode_32bit_int()

reg2=decoder.decode_32bit_int()

latitude=float(reg1)/10000000

longitude=float(reg2)/10000000

(Strange 5.s are appearing in some code snippets they should not be there, please ignore)

This is the first half of a file location.py stored in /var/www/venus

The second half returns the information in an html page like this

#got the location so send HTTP redirect to display in google maps

print "Content-Type: text/html"

print """\

<html>

 <head>

  <title>Lady's Smock Location</title>

 </head>

 <body>

<h1>Where is Lady's Smock</h1>

"""

print("<a href='https://www.google.com/maps/?f=q&q=%f,%f&z=17'>Boat Location</a>" % (latitude, longitude))

print("<br>Latitude %f Longitude %f" % (latitude, longitude))

print """\

 </body>

</html>

"""

Note that you do not need to set execute access on the file, the server CGI handler will take care of running the file. However it is useful to set execute access (chmod 775 location.py) to test run the file for errors. Remember to remove the execute access (chmod -x location.py) when you have finished testing.

Accessing http://<GX IP address>/location.py displays the following.

And clicking on the link displays the location in google maps.

Alternative html responses

As an alternative you can issue an HTTP or HTML redirect to go to google maps like this.

#got the location so send HTTP redirect to display in google maps

print "status: 303 refer other"

print "Content-Type: text/html"

print("location: https://www.google.com/maps/?f=q&q=%f,%f&z=17" % (latitude, longitude))

#Keep Hiawatha server happy with blank content

print """\

<html>

<body>

</body>

</html>

"""

or like this

#got the location so send redirect to display in google

print """\

Content-Type: text/html

<html>

"""

print("<meta http-equiv='refresh' content='0;url=https://www.google.com/maps?f=q&q=%f,%f' />" % (latitude, longitude))

print """\

</head>

<body>

you should have been redirected

</body>

</html>

"""

Accessing either of these pages should redirect immediately to a google map showing the location.

Embedding location information in other web pages

If you want to use the location information embedded in other web pages then you need to us a google maps embed API as described in: https://developers.google.com/maps/documentation/embed/get-api-key

This adds only a little more complication like this.

apikey = "your secret key from google"

#got the location so send redirect to display in google

print """\

Content-Type: text/html

<html>

<body>"""

print("<iframe src='https://www.google.com/maps/embed/v1/place?key=%s&q=%f,%f' width='100%%' height='96%%'/>" % (apikey, latitude, longitude))

print """\

</iframe>

</body>

</html>

"""

(Strange 5.s are appearing in some code snippets they should not be there, please ignore)

This creates a response which embeds the google map in an iframe you can then embed that iframe in your own web pages like this:

<iframe src="http://<domain address of your GX device>/map-iframe.py" width="640" height="480"></iframe>

On our boats webpage this will look like this:

Finally

Remember that all changes to /var/www and /etc will be lost after an upgrade (I hope to do a post soon about storing all changes on a removable USB memory stick so that you can re apply changes easily after any upgrade)

"On the Back's of Giants" None of what I have done here would have been possible without the assistance of many others who have posted their code snippets to the internet in "Stackexchange" the Victron Community and other locations I freely acknowledge their contributions and make this post in the same spirit - Enjoy.

Venus GX - VGXVenus OSModbus TCP
2 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

1 Answer
mvader (Victron Energy) avatar image
mvader (Victron Energy) answered ·

Hi cool!


some tips:


1) you dont need a usb stick to store permanent files, use the data partition. See the root access document for information.


2) nice trick with the modbustcp. Note that you could consider using dbus instead; Doing so would be cleaner (it would skip a few translations); but that just some optimisation.

Lastly I would use VRM, but I suppose the goal of all this is to avoid using VRM?


have a good day, Matthijs

1 comment
2 |3000 characters needed characters left characters exceeded

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

I had a look at the D-Bus implementation and it does simplify the code save a number of lines and translations here is the revised code to get the location using D-Bus.

Also a good example of how to make simple python calls to D-Bus.

Keywords: Venus OS, DBus, Python

#!/usr/bin/python

import dbus

bus = dbus.SystemBus()

lat = bus.get_object('com.victronenergy.gps', '/Position/Latitude')

long = bus.get_object('com.victronenergy.gps', '/Position/Longitude')

latitude = lat.GetValue() 

longitude = long.GetValue()

The other sections of the code in the post above can then be used.