Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/lora: Enable LoraWAN supported hardware #537

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ build_flags =
build_partitions = min_spiffs.csv
build_partitions_debug = min_spiffs_debug.csv

# Used for LoRaWAN builds
# https://github.com/mcci-catena/arduino-lmic#selecting-the-lorawan-region-configuration
lora_lib =
MCCI LoRaWAN LMIC library
aparcar/CayenneLPP@^1.3.0
lora_build_flags =
-D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS
-D hal_init=LMICHAL_init ; Workaround mcci arduino-lmic bug 714 on esp32
-D CFG_us915 ; USA 915Mhz
jeremypoulter marked this conversation as resolved.
Show resolved Hide resolved

neopixel_lib = adafruit/Adafruit NeoPixel@1.11.0


Expand Down Expand Up @@ -308,9 +318,14 @@ upload_speed = 921600

[env:openevse_esp32-heltec-wifi-lora-v2]
board = heltec_wifi_lora_32_V2
lib_deps =
${common.lib_deps}
${common.lora_lib}
build_flags =
${common.build_flags}
${common.src_build_flags}
${common.lora_build_flags}
${common.version}.dev
-D DEBUG_PORT=Serial
-D WIFI_LED=25
-D WIFI_LED_ON_STATE=HIGH
Expand All @@ -319,3 +334,10 @@ build_flags =
-D RAPI_PORT=Serial1
-D RX1=25
-D TX1=27
-D CFG_sx1276_radio ; SX1275 radio
-D ENABLE_LORA=1
-D LORA_NSS=18
-D LORA_RST=14
-D LORA_DIO0=26
-D LORA_DIO1=35
-D LORA_DIO2=34
10 changes: 10 additions & 0 deletions src/app_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ String mqtt_vehicle_range;
String mqtt_vehicle_eta;
String mqtt_announce_topic;

// LoraWAN network settings
String lora_deveui;
String lora_appeui;
String lora_appkey;

// OCPP 1.6 Settings
String ocpp_server;
String ocpp_chargeBoxId;
Expand Down Expand Up @@ -194,6 +199,11 @@ ConfigOpt *opts[] =
// RFID storage
new ConfigOptDefenition<String>(rfid_storage, "", "rfid_storage", "rs"),

// Lora settings
new ConfigOptDefenition<String>(lora_deveui, "", "lora_deveui", "lde"),
new ConfigOptDefenition<String>(lora_appeui, "", "lora_appeui", "lae"),
new ConfigOptDefenition<String>(lora_appeui, "", "lora_appkey", "lak"),

#if RGB_LED
// LED brightness
new ConfigOptDefenition<uint8_t>(led_brightness, LED_DEFAULT_BRIGHTNESS, "led_brightness", "lb"),
Expand Down
10 changes: 10 additions & 0 deletions src/app_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ extern String mqtt_vehicle_range;
extern String mqtt_vehicle_eta;
extern String mqtt_announce_topic;

// LoraWAN Settings
extern String lora_deveui;
extern String lora_appeui;
extern String lora_appkey;

// OCPP 1.6 Settings
extern String ocpp_server;
extern String ocpp_chargeBoxId;
Expand Down Expand Up @@ -109,6 +114,7 @@ extern uint32_t flags;
#define CONFIG_OCPP_AUTO_AUTH (1 << 22)
#define CONFIG_OCPP_OFFLINE_AUTH (1 << 23)
#define CONFIG_THREEPHASE (1 << 24)
#define CONFIG_LORA (1 << 25)


inline bool config_emoncms_enabled() {
Expand Down Expand Up @@ -139,6 +145,10 @@ inline bool config_mqtt_reject_unauthorized() {
return 0 == (flags & CONFIG_MQTT_ALLOW_ANY_CERT);
}

inline bool config_lora_enabled() {
return CONFIG_LORA == (flags & CONFIG_LORA);
}

inline bool config_ocpp_enabled() {
return CONFIG_SERVICE_OCPP == (flags & CONFIG_SERVICE_OCPP);
}
Expand Down
183 changes: 183 additions & 0 deletions src/lora.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
kallisti5 marked this conversation as resolved.
Show resolved Hide resolved
* Copyright (c) 2019-2020 Alexander von Gluck IV for OpenEVSE
*
* -------------------------------------------------------------------
*
* Additional Adaptation of OpenEVSE ESP Wifi
* by Trystan Lea, Glyn Hudson, OpenEnergyMonitor
* All adaptation GNU General Public License as below.
*
* -------------------------------------------------------------------
*
* This file is part of Open EVSE.
* Open EVSE is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
* Open EVSE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Open EVSE; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef ENABLE_LORA

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

#include "emonesp.h"
#include "input.h"
#include "lora.h"

#include "app_config.h"


#define LORA_HTOI(c) ((c<='9')?(c-'0'):((c<='F')?(c-'A'+10):((c<='f')?(c-'a'+10):(0))))
#define LORA_TWO_HTOI(h, l) ((LORA_HTOI(h) << 4) + LORA_HTOI(l))
#define LORA_HEX_TO_BYTE(a, h, n) { for (int i = 0; i < n; i++) (a)[i] = LORA_TWO_HTOI(h[2*i], h[2*i + 1]); }
#define LORA_DEVADDR(a) (uint32_t) ((uint32_t) (a)[3] | (uint32_t) (a)[2] << 8 | (uint32_t) (a)[1] << 16 | (uint32_t) (a)[0] << 24)

// Announce every 15 minutes
#define ANNOUNCE_INTERVAL 900 * 1000 // (In Milliseconds)


// LoRa module pin mapping
const lmic_pinmap lmic_pins = {
.nss = LORA_NSS,
.rxtx = LMIC_UNUSED_PIN,
.rst = LORA_RST,
.dio = {LORA_DIO0, LORA_DIO1, LORA_DIO2},
};

// Used for OTAA, not used (yet)
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }

void
create_rapi_cayennelpp(EvseManager* _evse, CayenneLPP* lpp)
{
if (_evse == NULL) {
DBUGF("Corrupt EvseManager!")
return;
}
if (lpp == NULL) {
DBUGF("Corrupt CayenneLPP buffer!")
return;
}

lpp->reset();
lpp->addDigitalInput(0, _evse->getEvseState());
lpp->addAnalogInput(1, _evse->getVoltage());
lpp->addAnalogInput(2, _evse->getAmps());
lpp->addAnalogInput(3, _evse->getChargeCurrent());
lpp->addDigitalInput(4, _evse->getSessionElapsed() / 60);
if(evse.isTemperatureValid(EVSE_MONITOR_TEMP_MONITOR))
lpp->addTemperature(5, _evse->getTemperature(EVSE_MONITOR_TEMP_MONITOR) * TEMP_SCALE_FACTOR);
if(evse.isTemperatureValid(EVSE_MONITOR_TEMP_MAX))
lpp->addTemperature(6, _evse->getTemperature(EVSE_MONITOR_TEMP_MAX) * TEMP_SCALE_FACTOR);
}

/// Reset LoRa modem. Reload LoRaWAN keys
void onEvent(ev_t ev) {
switch (ev) {
case EV_TXCOMPLETE:
DBUGF("LoRa: TX Complete.");
// LoRaWAN transmission complete
if (LMIC.txrxFlags & TXRX_ACK) {
// Received ack
DBUGF("LoRa: TX ack.");
}
break;
case EV_TXSTART:
DBUGF("LoRa: TX Begin.");
break;
default:
// Ignore anything else for now
break;
}
}

LoraTask::LoraTask()
:
MicroTasks::Task()
{
}

void
LoraTask::begin(EvseManager &evse)
{
_evse = &evse;
MicroTask.startTask(this);
}

/// Initial setup of LoRa modem.
void
LoraTask::setup()
{
Profile_Start(LoraTask::setup);

os_init();
modem_reset();

Profile_End(LoraTask::setup, 1);
}

/// Reset LoRa modem. Reload LoRaWAN keys
void
LoraTask::modem_reset()
{
Profile_Start(LoraTask::modem_reset);
// LoRaWAN credentials to use
uint8_t DEVADDR[4];
uint8_t NWKSKEY[16];
uint8_t APPSKEY[16];

LORA_HEX_TO_BYTE(DEVADDR, lora_deveui.c_str(), 4);
LORA_HEX_TO_BYTE(NWKSKEY, lora_appeui.c_str(), 16);
LORA_HEX_TO_BYTE(APPSKEY, lora_appkey.c_str(), 16);

LMIC_reset();
LMIC_setSession (0x13, LORA_DEVADDR(DEVADDR), NWKSKEY, APPSKEY);
LMIC_setAdrMode(0);
LMIC_setClockError(MAX_CLOCK_ERROR * 10 / 100);
LMIC_selectSubBand(1);
LMIC_setLinkCheckMode(0);
LMIC.dn2Dr = DR_SF7;
Profile_End(LoraTask::modem_reset, 1);
}

/// Announce our status to LoraWAN if it's time
void
LoraTask::publish(CayenneLPP* lpp)
{
Profile_Start(LoraTask::publish);
DBUGF("LoRa: Starting LoRaWAN broadcast...");
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
DBUGF("LoRa: Modem busy. Retry later");
return;
}
LMIC_setTxData2(1, lpp->getBuffer(), lpp->getSize(), false);
Profile_End(LoraTask::publish, 1);
}

unsigned long
LoraTask::loop(MicroTasks::WakeReason reason)
{
if (!config_lora_enabled())
return MicroTask.Infinate;

CayenneLPP lpp(24);
create_rapi_cayennelpp(_evse, &lpp);
lora.publish(&lpp);
return ANNOUNCE_INTERVAL;
}

LoraTask lora;

#endif /* ENABLE_LORA */
55 changes: 55 additions & 0 deletions src/lora.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2019-2023 Alexander von Gluck IV for OpenEVSE
*
* -------------------------------------------------------------------
*
* Additional Adaptation of OpenEVSE ESP Wifi
* by Trystan Lea, Glyn Hudson, OpenEnergyMonitor
* All adaptation GNU General Public License as below.
*
* -------------------------------------------------------------------
*
* This file is part of Open EVSE.
* Open EVSE is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
* Open EVSE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Open EVSE; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef ENABLE_LORA
#ifndef _LORA_H
#define _LORA_H

#include <CayenneLPP.h>
#include <MicroTasks.h>

#include "evse_man.h"

void create_rapi_cayennelpp(EvseManager* _evse, CayenneLPP* lpp);

class LoraTask : public MicroTasks::Task {
private:
EvseManager* _evse;

protected:
void setup();
unsigned long loop(MicroTasks::WakeReason reason);
void publish(CayenneLPP* lpp);
void modem_reset();

public:
LoraTask();
void begin(EvseManager &evse);
};

extern LoraTask lora;

#endif // _LORA_H
#endif /* ENABLE_LORA */
6 changes: 6 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "divert.h"
#include "ota.h"
#include "lcd.h"
#include "lora.h"
#include "openevse.h"
#include "root_ca.h"
#include "espal.h"
Expand Down Expand Up @@ -160,6 +161,11 @@ void setup()

ocpp.begin(evse, lcd, eventLog, rfid);

#ifdef ENABLE_LORA
// initialise LoRA if supported
lora.begin(evse);
#endif

shaper.begin(evse);

lcd.display(F("OpenEVSE WiFI"), 0, 0, 0, LCD_CLEAR_LINE);
Expand Down