diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5db9870 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +assets +*.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..2417e0e --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# TwizyChargeThrottle + +This is a very simple tool to limit the Twizy charge current if you don't have an OVMS. + +It can currently only limit the charge current to a fixed level (defined in the config file). + +The Arduino needs to be connected to the Twizy CAN bus during the charge process to be able +to actively overwrite the charge current control frames. + +Note: using an interrupt capable CAN shield is highly recommended. + + +## Info + +Author: Michael Balzer + +Libraries used: + - MCP_CAN: https://github.com/coryjfowler/MCP_CAN_lib + +This is free software under GNU Lesser General Public License (LGPL) +https://www.gnu.org/licenses/lgpl.html diff --git a/TwizyChargeThrottle/TwizyChargeThrottle.ino b/TwizyChargeThrottle/TwizyChargeThrottle.ino new file mode 100644 index 0000000..1f38339 --- /dev/null +++ b/TwizyChargeThrottle/TwizyChargeThrottle.ino @@ -0,0 +1,147 @@ +/** + * ========================================================================== + * Twizy charge current throttle + * ========================================================================== + * + * Author: Michael Balzer + * + * Libraries used: + * - MCP_CAN: https://github.com/coryjfowler/MCP_CAN_lib + * + * License: + * This is free software under GNU Lesser General Public License (LGPL) + * https://www.gnu.org/licenses/lgpl.html + * + */ +#define TWIZY_CT_VERSION "V1.0 (2019-05-10)" + +#include +#include +#include "TwizyChargeThrottle_config.h" + +// CAN interface: +MCP_CAN CAN(TWIZY_CAN_CS_PIN); + +// CAN msg buffer: +unsigned long msgId; +byte msgLen; +byte msgBuf[8]; + +// Operation mode: +bool charging = false; + +// Current level: +byte level = 0; + + +#if TWIZY_CAN_IRQ_PIN > 0 +volatile bool msgReceived = false; +void canISR() { + msgReceived = true; +} +#endif + + +void setup() { + + Serial.begin(SERIAL_SPEED); + Serial.println(F("TwizyChargeThrottle " TWIZY_CT_VERSION)); + + // Init CAN interface: + + #if TWIZY_CAN_IRQ_PIN > 0 + pinMode(TWIZY_CAN_IRQ_PIN, INPUT); + attachInterrupt(digitalPinToInterrupt(TWIZY_CAN_IRQ_PIN), canISR, FALLING); + #endif + + while (CAN.begin(MCP_STDEXT, CAN_500KBPS, TWIZY_CAN_MCP_FREQ) != CAN_OK) { + Serial.println(F("Setup: waiting for CAN connection...")); + delay(1000); + } + + // Set ID filters: + + CAN.init_Mask(0, 0, 0x07FF0000); + CAN.init_Filt(0, 0, 0x01550000); // BMS → BMS: current control + CAN.init_Filt(1, 0, 0x05970000); // CHG → BMS: operation mode + + CAN.init_Mask(1, 0, 0x07FF0000); + CAN.init_Filt(2, 0, 0x00000000); + CAN.init_Filt(3, 0, 0x00000000); + CAN.init_Filt(4, 0, 0x00000000); + CAN.init_Filt(5, 0, 0x00000000); + + CAN.setMode(MCP_NORMAL); + + Serial.println(F("Setup done.")); + + Serial.print(F("Throttling configured to current level: ")); + Serial.println((char)('0' + TWIZY_CHARGE_THROTTLE)); +} + + +void loop() { + while (true) { + + #if TWIZY_CAN_IRQ_PIN > 0 + // Wait for interrupt signal: + while (!msgReceived); + msgReceived = false; + #endif + + // Process CAN read buffer: + while (CAN.readMsgBuf(&msgId, &msgLen, msgBuf) == CAN_OK) + { + if (msgId == 0x597) + { + // ID 0x597: operation mode + + bool _charging = ((msgBuf[1] & 0x60) == 0x20); + + #if TWIZY_DEBUG > 0 + if (_charging && !charging) + Serial.println(F("Charge START")); + else if (!_charging && charging) + Serial.println(F("Charge STOP")); + #endif + + charging = _charging; + level = 0; + } + else if (charging) + { + // ID 0x155: charge current control + + byte _level = msgBuf[0]; + + if (_level == 0xFF) + continue; // init phase, skip + + if (_level > TWIZY_CHARGE_THROTTLE) + { + // overwrite: + msgBuf[0] = TWIZY_CHARGE_THROTTLE; + CAN.sendMsgBuf(0x155, 0, 8, msgBuf); + } + + #if TWIZY_DEBUG > 1 + if (_level != level) + { + Serial.print(F("Level ")); + if (_level > TWIZY_CHARGE_THROTTLE) { + Serial.print((char)('0' + _level)); + Serial.print('>'); + Serial.println((char)('0' + TWIZY_CHARGE_THROTTLE)); + } else { + Serial.println((char)('0' + _level)); + } + } + #endif + + level = _level; + } + } + + } // while (true) +} + diff --git a/TwizyChargeThrottle/TwizyChargeThrottle_config.h b/TwizyChargeThrottle/TwizyChargeThrottle_config.h new file mode 100644 index 0000000..8694194 --- /dev/null +++ b/TwizyChargeThrottle/TwizyChargeThrottle_config.h @@ -0,0 +1,36 @@ +/** + * ========================================================================== + * Twizy charge current throttle + * ========================================================================== + */ +#ifndef _TwizyChargeThrottle_config_h +#define _TwizyChargeThrottle_config_h + +// Set the charge current throttle level here: +// 6 = 30 A = 2,1 kW +// 5 = 25 A = 1,7 kW +// 4 = 20 A = 1,4 kW +// 3 = 15 A = 1,0 kW +// 2 = 10 A = 0,7 kW +// 1 = 5 A = 0,4 kW +#define TWIZY_CHARGE_THROTTLE 5 + +// Serial debug output level: +// 1 = show charge start/stop +// 2 = show current level changes +#define TWIZY_DEBUG 2 + +// Serial interface baud rate: +#define SERIAL_SPEED 115200 + +// Set your CAN MCP clock frequency here: +#define TWIZY_CAN_MCP_FREQ MCP_16MHZ + +// Set your CAN CS pin number here: +#define TWIZY_CAN_CS_PIN SS + +// Set your CAN IRQ pin here (0 = no IRQ): +#define TWIZY_CAN_IRQ_PIN 2 + +#endif // _TwizyChargeThrottle_config_h +