2018-11-20, 05:11 PM
Okay. The display is an I2C 20x4 LCD display. They are available for very little from places like Amazon or Aliexpress.
The controller is indeed an ESP32. This one is a DOIT DEVKIT V1, but there are lots of generic modules available that will do the same thing. Since all you need in terms of IO are the two I2C connections and a 3.3V/GND, the connections are pretty simple. I would guess that what you are seeing the picture doesn't cost more than around $12 USD for everything.
As I said, I'm still searching for a decent case for it all.
I programmed this using the Arduino IDE. Here is the code:
Good luck!
Andy
The controller is indeed an ESP32. This one is a DOIT DEVKIT V1, but there are lots of generic modules available that will do the same thing. Since all you need in terms of IO are the two I2C connections and a 3.3V/GND, the connections are pretty simple. I would guess that what you are seeing the picture doesn't cost more than around $12 USD for everything.
As I said, I'm still searching for a decent case for it all.
I programmed this using the Arduino IDE. Here is the code:
Code:
/*
Basic MQTT Connection for NMEA
*/
#include <WiFi.h>
#include <WiFiClient.h>
#include <PubSubClient.h>
#include <TinyGPS++.h>
#include <LiquidCrystal_I2C.h>
// Update these with values suitable for your network.
const char * ssid = "<YOUR WIFI SSID>";
const char * password = "<YOUR WIFI PASSWORD>";
const char * mqtt_server = "<YOUR MQTT SERVER IP ADDRESS>";
// The TinyGPS++ object
TinyGPSPlus gps;
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
// set the LCD number of columns and rows
int lcdColumns = 20;
int lcdRows = 4;
String DBT = "";
String northSouth = "N ";
String eastWest = "E ";
double latRaw;
double lonRaw;
String latiTude = "";
String longiTude = "";
// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
//Create the knot character
byte customChar[8] = {
0b10000,
0b10100,
0b11000,
0b10100,
0b00010,
0b00111,
0b00010,
0b00011
};
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
lcd.setCursor(0,0);
lcd.print("SSID: ");
Serial.println(ssid);
lcd.setCursor(7,0);
lcd.print(ssid);
WiFi.begin(ssid, password);
int dot_cur = 0;
lcd.setCursor(0,1);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
lcd.print(".");
}
randomSeed(micros());
Serial.println("");
lcd.clear();
Serial.println("WiFi connected");
lcd.setCursor(0,0);
lcd.print("WiFi connected");
Serial.println("IP address: ");
lcd.setCursor(0,2);
lcd.print("IP: ");
Serial.println(WiFi.localIP());
lcd.setCursor(5,2);
lcd.print(WiFi.localIP());
}
void setup_lcd(){
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
// set cursor to first column, first row
lcd.setCursor(0, 0);
}
void callback(char* topic, byte* payload, unsigned int length) {
for (int i=0;i<length;i++) {
if (gps.encode(*payload++))
displayInfo();
}
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
client.subscribe("inTopic"); // whatever the topic name is for your NMEA stream from your MQTT server.
//arrow characters in the upper right when MQTT is connected
lcd.setCursor(19,0);
lcd.print(char(127));
lcd.setCursor(19,1);
lcd.print(char(126));
delay(500);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
lcd.setCursor(0,1);
lcd.print("MQTT Failed");
lcd.setCursor(0,2);
lcd.print("rc=");
lcd.print(client.state());
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_lcd();
// create a new custom character for knot
lcd.createChar(0, customChar);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
//Delay 5 secs so we can see what happened
delay (5000);
lcd.clear();
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
void displayInfo()
{
Serial.print(F("Location: "));
if (gps.location.isValid())
{
latRaw = gps.location.lat();
Serial.print(latRaw);
if (latRaw < 0){
northSouth = "S ";
}
else
{
northSouth = "N ";
}
latRaw = abs(latRaw);
int latDeg = latRaw;
Serial.println(latDeg);
double latMins = (latRaw - latDeg) * 60;
Serial.println(latMins);
latiTude = northSouth;
if (latDeg < 100){
latiTude += " ";
}
else if (latDeg < 10) {
latiTude += " ";
}
latiTude += latDeg;
latiTude += char(223);
if (latMins <10)
latiTude += " ";
latiTude += String(latMins,3);
latiTude += "\' ";
lcd.setCursor(0,0);
lcd.print("LAT: ");
lcd.print(latiTude);
Serial.print(F(","));
Serial.print(gps.location.lng(), 6);
lonRaw = gps.location.lng();
if (lonRaw < 0){
eastWest = "W ";
}
else
{
eastWest = "E ";
}
lonRaw = abs(lonRaw);
int lonDeg = lonRaw;
double lonMins = (lonRaw - lonDeg) * 60;
longiTude = eastWest;
if (lonDeg < 100){
longiTude += " ";
}
else if (lonDeg < 10) {
longiTude += " ";
}
longiTude += lonDeg;
longiTude += char(223);
if (lonMins < 10)
longiTude += " ";
longiTude += String(lonMins,3);
longiTude += "\' ";
lcd.setCursor(0,1);
lcd.print("LON: ");
lcd.print(longiTude);
}
else
{
Serial.print(F("INVALID"));
lcd.setCursor(0,0);
lcd.print("========NAN========");
lcd.setCursor(0,1);
lcd.print("========NAN========");
}
if (gps.speed.isValid()) {
lcd.setCursor(10,2);
lcd.print("SOG: ");
lcd.print(gps.speed.knots(),1);
//lcd.print("K");
lcd.write((uint8_t)0);
if (gps.speed.knots() < 10){
lcd.print(" ");
}
}
else
{
Serial.print(F("INVALID"));
lcd.setCursor(10,2);
lcd.print("===NAN===");
}
if (gps.course.isValid()){
Serial.println("");
Serial.print(F("COG="));
lcd.setCursor(0,2);
lcd.print("COG: ");
Serial.println(gps.course.deg());
lcd.print(gps.course.deg(), 0);
lcd.print(char(223));
if (gps.course.deg()<10){
lcd.print(" ");
}
else if (gps.course.deg()<100){
lcd.print(" ");
}
}
else
{
Serial.print(F("INVALID"));
lcd.setCursor(0,2);
lcd.print("==NAN==");
}
Serial.print(F(" Date/Time: "));
if (gps.date.isValid())
{
lcd.setCursor(10,3);
Serial.print(gps.date.month());
lcd.print(gps.date.month());
Serial.print(F("/"));
lcd.print(F("/"));
Serial.print(gps.date.day());
lcd.print(gps.date.day());
Serial.print(F("/"));
lcd.print(F("/"));
Serial.print(gps.date.year());
lcd.print(gps.date.year());
}
else
{
Serial.print(F("INVALID"));
lcd.setCursor(10,3);
lcd.print("===NAN===");
}
Serial.print(F(" "));
if (gps.time.isValid())
{
lcd.setCursor(0,3);
if (gps.time.hour() < 10) {
Serial.print(F("0"));
lcd.print(F("0"));
}
lcd.print(gps.time.hour());
Serial.print(gps.time.hour());
Serial.print(F(":"));
lcd.print(":");
if (gps.time.minute() < 10){
Serial.print(F("0"));
lcd.print(F("0"));
}
Serial.print(gps.time.minute());
lcd.print(gps.time.minute());
Serial.print(F(":"));
lcd.print(":");
if (gps.time.second() < 10) {
Serial.print(F("0"));
lcd.print(F("0"));
}
Serial.print(gps.time.second());
lcd.print(gps.time.second());
Serial.print(F("."));
if (gps.time.centisecond() < 10){
Serial.print(F("0"));
}
Serial.print(gps.time.centisecond());
lcd.print("Z");
}
else
{
Serial.print(F("INVALID"));
lcd.setCursor(0,3);
lcd.print("===NAN===");
}
Serial.println();
}
Andy