OK. All is working now. The Arduino and MCP2515 listens successfully for messages from the SeeLevel.
I have it driving 4 APA106 LEDs using the FastLED library and reading a button.
The LEDs indicate 3 tank levels and flash an alarm LED when any of the tanks read above/below a certain level. I've installed the LEDs in a Marine switch blank cover. The SeeLevel can't be seen from the kitchen. So I'll mount this display in easy view of the kitchen.
The installed hardware will be a 16MHz Arduino Pro Micro and a MCP25625 (code compatible with MCP2515) shield that will fit on the Pro Micro board.
There's still some code that you provided that isn't necessarily required for what I need. But it's still in there.
Code: Select all
/*
SeeLevel Alarm monitor for 5V/16MHz Pro Mini or Pro Micro
by: Jim Minihane
rev: 1.0
date: 2020-05-14
Based on...
RV-C CAN_Bus_Monitor
by: Michael J. Kidd <linuxkidd@gmail.com>
Rev: 1.0
Date: 2015-11-23
*/
#include <FastLED.h>
#include <mcp_can.h>
#include <SPI.h>
#define DEBUG // Enable debug output
#define BUTTON_PIN 7
// FastLED defines
#define NUM_LEDS 4
#define DATA_PIN 8
#define RGB_ORDER RGB
#define ALARM_ON_COUNTS 100
#define ALARM_OFF_COUNTS 100
#define tankGREEN 0x000F00
#define tankYELLOW 0x0F0F00
#define tankRED 0x0F0000
#define tankOFF 0x000000
#define alarmCOLOR1 0xFF0000
#define alarmCOLOR2 0x0000FF
#define alarmOFF 0x000000
#define ledALARM 0
#define ledFRESH 1
#define ledGREY 2
#define ledBLACK 3
#define SPI_CS_PIN 10 // Which pin to use for SPI CS with CAN bus interface
/*
* Variables below this point are used internally and should not be changed.
*/
uint8_t len = 0;
uint8_t buf[8];
uint8_t alarm_state = 0;
uint8_t alarm_updown = 0;
uint16_t alarm_counter = 0;
uint32_t canId = 0x000;
char outbuf[8];
char outbuf2[32];
char hexDGN[6];
unsigned int bin2int(char * digits);
char* int2bin(uint32_t d);
void parseTank();
CRGB leds[NUM_LEDS]; // Led pixel array
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
typedef struct {
uint8_t level_alert = 0;
uint8_t level_alarm = 0;
uint8_t level_num = 0;
uint8_t alarm_last = 0;
uint8_t alarm_current = 0;
} tank;
tank fresh;
tank grey;
tank black;
typedef struct {
char prio[4];
char dgnhi[10];
char dgnlo[9];
char srcAD[9];
} packetmeta;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP);
FastLED.addLeds<WS2812B, DATA_PIN, RGB_ORDER>(leds, NUM_LEDS);
FastLED.setCorrection(0xFFFFFF); // TypicalLEDStrip);
FastLED.setTemperature(Tungsten100W);
FastLED.setDither(0);
FastLED.setBrightness(255);
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
#ifdef DEBUG
Serial.begin(115200);
#endif
START_INIT:
#ifdef DEBUG
Serial.println(F("CAN Begin..."));
#endif
if (CAN_OK == CAN.begin(CAN_250KBPS, MCP_8MHz)){
CAN.init_Mask(0, 1, 0);
CAN.init_Mask(1, 1, 0);
for (int i = 0; i < 6; i++) {
CAN.init_Filt(i, 1, 0);
}
#ifdef DEBUG
Serial.println(F("CAN BUS Shield init ok!"));
#endif
}
else {
#ifdef DEBUG
Serial.println(F("CAN BUS Shield init fail"));
Serial.println(F("Init CAN BUS Shield again"));
#endif
delay(100);
goto START_INIT;
}
fresh.level_alarm = 17;
fresh.level_alert = 35;
grey.level_alarm = 80;
grey.level_alert = 60;
black.level_alarm = 80;
black.level_alert = 60;
} // Setup
void loop() {
if (digitalRead(BUTTON_PIN) == 1) {
alarm_state = 0;
}
if (CAN_MSGAVAIL == CAN.checkReceive()) {
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();
char *binCanID=int2bin(canId);
packetmeta p;
// Separate the overloaded canID
memcpy(p.prio, &binCanID[0], 3);
memcpy(p.dgnhi, &binCanID[4], 9);
memcpy(p.dgnlo, &binCanID[13],8);
memcpy(p.srcAD, &binCanID[21],8);
// Terminate all the char strings
p.prio[3]='\0';
p.dgnhi[9]='\0';
p.dgnlo[8]='\0';
p.srcAD[8]='\0';
free(binCanID);
sprintf(hexDGN, "%03X%02X", // Construct full hexDGN
bin2int(p.dgnhi),
bin2int(p.dgnlo));
/*
#ifdef DEBUG
sprintf(outbuf2, "%X,%03X%02X,%02X,%d,",
bin2int(p.prio),
bin2int(p.dgnhi),
bin2int(p.dgnlo),
bin2int(p.srcAD),
len);
//Serial.print(millis()); Serial.print(",");
Serial.println(canId, HEX);
Serial.print(outbuf2);
for (int i = 0; i < len; i++) {
sprintf(outbuf, "%02X", buf[i]);
Serial.print(outbuf);
}
Serial.println();
#endif
*/
if (strncmp(hexDGN,"1FFB7", 5) == 0 ){
parseTank();
#ifdef DEBUG
Serial.print(F("black.level_num: "));
Serial.println(black.level_num,DEC);
Serial.print(F("grey.level_num: "));
Serial.println(grey.level_num,DEC);
Serial.print(F("fresh.level_num: "));
Serial.println(fresh.level_num,DEC);
#endif
if (fresh.level_num < fresh.level_alarm){
fresh.alarm_current = 1;
if (fresh.alarm_current > fresh.alarm_last){
alarm_state = 1;
fresh.alarm_last = fresh.alarm_current;
}
leds[ledFRESH] = CRGB(tankRED);
}
else if (fresh.level_num < fresh.level_alert){
fresh.alarm_current = 0;
if (fresh.alarm_current < fresh.alarm_last){
fresh.alarm_last = fresh.alarm_current;
}
leds[ledFRESH] = CRGB(tankYELLOW);
}
else {
fresh.alarm_current = 0;
if (fresh.alarm_current < fresh.alarm_last){
fresh.alarm_last = fresh.alarm_current;
}
leds[ledFRESH] = CRGB(tankGREEN);
}
if (grey.level_num > grey.level_alarm){
grey.alarm_current = 1;
if (grey.alarm_current > grey.alarm_last){
alarm_state = 1;
grey.alarm_last = grey.alarm_current;
}
leds[ledGREY] = CRGB(tankRED);
}
else if (grey.level_num > grey.level_alert){
grey.alarm_current = 0;
if (grey.alarm_current < grey.alarm_last){
grey.alarm_last = grey.alarm_current;
}
leds[ledGREY] = CRGB(tankYELLOW);
}
else {
grey.alarm_current = 0;
if (grey.alarm_current < grey.alarm_last){
grey.alarm_last = grey.alarm_current;
}
leds[ledGREY] = CRGB(tankGREEN);
}
if (black.level_num > black.level_alarm){
black.alarm_current = 1;
if (black.alarm_current > black.alarm_last){
alarm_state = 1;
black.alarm_last = black.alarm_current;
}
leds[ledBLACK] = CRGB(tankRED);
}
else if (black.level_num > black.level_alert){
black.alarm_current = 0;
if (black.alarm_current < black.alarm_last){
black.alarm_last = black.alarm_current;
}
leds[ledBLACK] = CRGB(tankYELLOW);
}
else {
black.alarm_current = 0;
if (black.alarm_current < black.alarm_last){
black.alarm_last = black.alarm_current;
}
leds[ledBLACK] = CRGB(tankGREEN);
}
if ((fresh.level_num > fresh.level_alert) && (grey.level_num < grey.level_alert) && (black.level_num < black.level_alert))
{
alarm_state = 0;
}
FastLED.show();
} //hexDGN,"1FFB7"
} // CAN Message Avail
if (alarm_state == 1){
if (alarm_updown == 0){
alarm_counter++;
leds[ledALARM] = CRGB(alarmCOLOR1);
if (alarm_counter == ALARM_ON_COUNTS){ //ON Time
alarm_updown = 1;
alarm_counter = 0;
}
}
else {
alarm_counter++;
leds[ledALARM] = CRGB(alarmCOLOR2);
if (alarm_counter == ALARM_OFF_COUNTS){ //OFF Time
alarm_updown = 0;
alarm_counter = 0;
}
}
FastLED.show();
}
else {
leds[ledALARM] = CRGB(alarmOFF);
FastLED.show();
} // alarm_state
} // End loop
/*
unsigned int bin2int(char * digits)
This function converts a string of binary bits to an int.
*/
unsigned int bin2int(char * digits) {
unsigned int res = 0;
int digits_len = strlen(digits);
for (int i = 0; i < digits_len; i++) {
if ((digits[digits_len - (i + 1)]) == '1')
res += (1 << i);
}
return res;
}
/*
* char* int2bin(uint32_t d)
* This funciton converts an Unsigned 32 bit int into a CHAR string of binary
*/
char* int2bin(uint32_t d) {
const char* mybins = "01";
int pos = 0;
// unsigned long int b;
char b[29];
char *c = (char*)malloc(29);
while(d > 0) {
b[pos]=mybins[d % 2];
d /= 2;
pos++;
}
while(pos<29) {
b[pos]=mybins[0];
pos++;
}
b[pos]='\0';
pos--;
for(int i=pos;i>=0;i--) {
c[pos-i]=b[i];
}
pos++;
c[pos]='\0';
return c;
}
/*
* parseTank()
* Reads Tank level and sets <tank>.level and <tank>.alarm values
*/
void parseTank() {
if (buf[0] == 0) { // Fresh water tank
fresh.level_num = (100*(uint16_t)buf[1]) / buf[2];
}
if (buf[0] == 1) { // Black water tank
black.level_num = (100*(uint16_t)buf[1]) / buf[2];
}
if (buf[0] == 2) { // Grey water tank
grey.level_num = (100*(uint16_t)buf[1]) / buf[2];
}
}
/*********************************************************************************************************
END FILE
*********************************************************************************************************/