That will be fun. Count me in! I'm looking forward to meet you geeks in person.
Let the nodes connect..
core_c
@core_c
a coder.. i love RISC assembler.
A cool project was: a DCC controller for digital model-trains (not my own hobby), running on an Atmel AVR.
For PC i coded mainly in Delphi and later C++. Some nice projects were: Creating a dedicated server for CMR4 (rally game), and working in a team for Wolfenstein ET (really cool feeling to make so many gamers happy).
I like photography.. I wish i learned to play an instrument (other than a computer), but i can paint and draw
I wish you a good life..
Best posts made by core_c
-
RE: MySensors booth at Eindhoven Maker Faire!
-
Software I2C slave for Arduino Uno & TFT shield (+code)
I created a software I2C-slave implementation for an Arduino Uno with a TFT-shield.
The TFT occupies all pins of the Arduino Uno.
The Uno's default designated (hardware) I2C pins can not be used, because they connect to the TFT's pins that control RESET & CS. If the hardware I2C would be used, the TFT would behave irratic.
I do not use the TFT's SD card, so i can use 2 of those pins for the (software) I²C bus.
Arduino pins used: 11 = SCL, 12 = SDA.
This software I2C bus operates at a +5V level.
Therefore connect the TFT I2C-slave at the high level side of the Logic Level Converter.I made a demo sketch for the slave, and a demo sketch for any other Arduino that acts as the master. The demo is simple: It just sends 5 float values to the slave, which displays it on the TFT.
Codesize is small and fast. It should not be hard to adjust the code to your own needs. The part of the code you edit, is normal Arduino code.Here's the I2C-slave TFT in action on my MySensors node, displaying the measurements:
Here is the sketch of the I2C-slave TFT:
// TFT #include <Adafruit_GFX.h> #include <UTFTGLUE.h> UTFTGLUE tft(0x9341,A2,A1,A3,A4,A0); #if !defined(SmallFont) extern uint8_t SmallFont[]; #endif #define BLACK 0x0000 #define WHITE 0xFFFF // I2C #define I2C_SLAVE_ADDRESS 73 #define SCL_BIT PB3 #define SDA_BIT PB4 #define I2C_DDR DDRB #define I2C_OUT PORTB #define I2C_IN PINB extern "C" { volatile uint8_t byteN; volatile uint8_t I2C_data; volatile union u_floatarray { uint8_t b[20]; float f[5]; } I2C_values; void InComingData(void) { I2C_values.b[byteN] = I2C_data; byteN++; if (byteN % 4 == 0) { uint8_t v = (byteN >> 2) - 1; uint8_t r = v * 8; tft.setCursor(80, r); tft.println(I2C_values.f[v]); } } void OutGoingData(void) { // nothing } } void setup() { tft.begin(); tft.InitLCD(); tft.setFont(SmallFont); tft.fillScreen(WHITE); if (tft.height() > tft.width()) tft.setRotation(1); tft.setTextColor(BLACK,WHITE); //black on white, instead of transparent chars.. tft.setTextSize(1); tft.setCursor(0, 0); tft.println("Temperature:"); tft.println(" Humidity:"); tft.println(" UV-index:"); tft.println("Light Level:"); tft.println(" Pressure:"); TIMSK0 = 0; __asm__ __volatile__ ( "cli" "\n" "cbi %[I2CDDR], %[SCLBIT]" "\n" "cbi %[I2COUT], %[SCLBIT]" "\n" "cbi %[I2CDDR], %[SDABIT]" "\n" "cbi %[I2COUT], %[SDABIT]" "\n" :: [I2CDDR] "I" (_SFR_IO_ADDR(I2C_DDR)), [I2COUT] "I" (_SFR_IO_ADDR(I2C_OUT)), [SCLBIT] "I" (SCL_BIT), [SDABIT] "I" (SDA_BIT) ); } void loop() { __asm__ __volatile__ ( "HandleTransaction:" "\n" "rcall I2C_activity" "\n" "brtc HandleTransaction" "\n" "StartCondition:" "\n" "ldi R16, 0" "\n" "sts byteN, R16" "\n" "rcall wait_SCL_low" "\n" "rcall slave_readByte" "\n" "brts StartCondition" "\n" "brhs StopCondition" "\n" "mov R19, R18" "\n" "lsr R19" "\n" "cpi R19, %[SLAVE_ADDR]" "\n" "brne StopCondition" "\n" "rcall slave_writeACK" "\n" "andi R18, 0b00000001" "\n" "brne MasterRead" "\n" "MasterWrite:" "\n" "rcall slave_readByte" "\n" "brts StartCondition" "\n" "brhs StopCondition" "\n" "rcall slave_writeACK" "\n" "sbi %[I2CDDR], %[SCLBIT]" "\n" "sts I2C_data, R18" "\n" "call InComingData" "\n" "cbi %[I2CDDR], %[SCLBIT]" "\n" "rjmp MasterWrite" "\n" "MasterRead:" "\n" "sbi %[I2CDDR], %[SCLBIT]" "\n" "call OutGoingData" "\n" "lds R18, I2C_data" "\n" "cbi %[I2CDDR], %[SCLBIT]" "\n" "rcall slave_writeByte" "\n" "brts StartCondition" "\n" "brhs StopCondition" "\n" "rcall slave_readACK" "\n" "breq MasterRead" "\n" "StopCondition:" "\n" "rjmp DoneTransaction" "\n" "I2C_activity:" "\n" "in R16, %[I2CIN]" "\n" "andi R16, (1<<%[SCLBIT] | 1<<%[SDABIT])" "\n" "ac1:" "in R17, %[I2CIN]" "\n" "andi R17, (1<<%[SCLBIT] | 1<<%[SDABIT])" "\n" "cp R16, R17" "\n" "breq ac1" "\n" "clh" "\n" "clt" "\n" "sbrs R16, %[SCLBIT]" "\n" "rjmp ac2" "\n" "sbrs R17, %[SCLBIT]" "\n" "rjmp ac2" "\n" "sbrs R17, %[SDABIT]" "\n" "set" "\n" "sbrc R17, %[SDABIT]" "\n" "seh" "\n" "ac2:" "ret" "\n" "slave_readByte:" "\n" "ldi R18, 0b00000001" "\n" "rb1:" "rcall wait_SCL_high" "\n" "in R19, %[I2CIN]" "\n" "rcall I2C_activity" "\n" "brts rb2" "\n" "brhs rb2" "\n" "sec" "\n" "sbrs R19, %[SDABIT]" "\n" "clc" "\n" "rol R18" "\n" "brcc rb1" "\n" "clz" "\n" "clh" "\n" "rb2:" "ret" "\n" "slave_writeByte:" "\n" "ldi R19, 8" "\n" "wb1:" "lsl R18" "\n" "brcs wb2" "\n" "sbi %[I2CDDR], %[SDABIT]" "\n" "wb2:" "brcc wb3" "\n" "cbi %[I2CDDR], %[SDABIT]" "\n" "wb3:" "rcall wait_SCL_high" "\n" "rcall I2C_activity" "\n" "brts wb4" "\n" "brhs wb4" "\n" "dec R19" "\n" "brne wb1" "\n" "wb4:" "cbi %[I2CDDR], %[SDABIT]" "\n" "ret" "\n" "skipPulse:" "\n" "rcall wait_SCL_high" "\n" "wait_SCL_low:" "\n" "sbic %[I2CIN], %[SCLBIT]" "\n" "rjmp wait_SCL_low" "\n" "ret" "\n" "wait_SCL_high:" "\n" "sbis %[I2CIN], %[SCLBIT]" "\n" "rjmp wait_SCL_high" "\n" "ret" "\n" "slave_writeACK:" "\n" "sbi %[I2CDDR], %[SDABIT]" "\n" "rcall skipPulse" "\n" "cbi %[I2CDDR], %[SDABIT]" "\n" "ret" "\n" "slave_readACK:" "\n" "rcall wait_SCL_high" "\n" "sez" "\n" "sbic %[I2CIN], %[SDABIT]" "\n" "clz" "\n" "rcall wait_SCL_low" "\n" "ret" "\n" "DoneTransaction:" "\n" :: [I2CIN] "I" (_SFR_IO_ADDR(I2C_IN)), [I2COUT] "I" (_SFR_IO_ADDR(I2C_OUT)), [I2CDDR] "I" (_SFR_IO_ADDR(I2C_DDR)), [SCLBIT] "I" (SCL_BIT), [SDABIT] "I" (SDA_BIT), [SLAVE_ADDR] "M" (I2C_SLAVE_ADDRESS), "e" (InComingData), "e" (OutGoingData), [I2C_data] "label" (I2C_data), [byteN] "label" (byteN) ); }
Here is a demo I2C-master sketch that sends the 5 floats:
#include <Wire.h> #define SLAVE_ADDRESS 73 union u_floatarray { uint8_t b[20]; float f[5]; } I2C_values; void setup() { // test values: temperature, humidity, UV-index, light level, pressure I2C_values.f[0] = 20.3; I2C_values.f[1] = 48.8; I2C_values.f[2] = 2.4; I2C_values.f[3] = 345.0; I2C_values.f[4] = 1019.7; pinMode(LED_BUILTIN, OUTPUT); Wire.begin(); } void loop() { delay(4000); digitalWrite(LED_BUILTIN, HIGH); Wire.beginTransmission(SLAVE_ADDRESS); for (uint8_t n=0; n<20; n++) if (Wire.write(I2C_values.b[n]) != 1) break; Wire.endTransmission(); digitalWrite(LED_BUILTIN, LOW); }
-
RE: Message is send twice
From your log i can see that your node goes to sleep, and immediately wakes up again.
I don't know the value of your SLEEP_TIME, but i guess it's not a value close to 0.
It looks like your sleep() cycle is interrupted by a change on your GENERATOR_PIN.
What if you inserted a short pause just before going to sleep, just after send(msgGENERATOR)?Another way to handle interrupts:
Your code uses an interrupt to detect changes of the generator status, but you handle possible changes outside the interrupt-handler (the code that is executed whenever there was a change on the pin). Your sleep function can exit in two ways: by interrupt OR by the SLEEP_TIME expiring. Your code does the same in both cases. Even if there was no change on the pin, but the timer expired, a message will be send.
If you only want to send a message when there was actually a change of signal on the pin, i would use an interrupt-handler that detects any change, and let the loop() code know about it.volatile bool generator_pin_changed = false; volatile int generator_pin_value; void generator_pin_interrupt_handler() { generator_pin_changed = true; generator_pin_value = digitalRead(GENERATOR_PIN); } void setup() { attachInterrupt(digitalPinToInterrupt(GENERATOR_PIN), generator_pin_interrupt_handler, CHANGE); } void loop() { if (generator_pin_changed) { generator_pin_changed = false; /* reset for next detection */ if (generator_pin_value == LOW) { Serial.println("Generator RUNNING"); send(msgGENERATOR.set(1)); } else { Serial.println("Generator NOT running - SENDING...."); send(msgGENERATOR.set(0)); } } wait(200); /* sleep again if the timer expired. stop sleeping if woken up by an interrupt. */ while (sleep(digitalPinToInterrupt(GENERATOR_PIN), CHANGE, SLEEP_TIME) < 0); }
-
RE: Rebuild of my broken 433mhz Cresta/hideki UV-Sensor
@sundberg84 You mention that you have an ATmega328.
In your sketch setup() function you set the reference voltage value:
analogReference(INTERNAL);
According to the Arduino Language Reference pages, [https://www.arduino.cc/en/Reference/AnalogReference](link url)
, on an ATmega328 that will set the analog reference value to 1.1V.
Any 10-bit sample taken by that ATmega328 will spread 1.1V out over 1024 values. In your code, you do the calculation using 3.3V as the AREF. That will produce 3 times smaller samplevalues as intended.I see quite some people using code derived from the UV-example-sketch.
The code is a bit tricky, and in my opinion: not correct.*) In your own code, you convert samplevalues to mV values: Very good. That should be done. The example does not do that.
*) The piece of code that returns the UV-index does this:
for (i=0; i<12; i++) if (voltage <= uvIndexValue[i]) { UV=float(i); break; }
It returns a value that is 1 index too high. (try it: 317 mV will return UV=2).
But later a fractional part of the UV-index is calculated, which corrects the initial (too high) value://calculate 1 decimal if possible if (i > 0) { float vRange = float(uvIndexValue[i] - uvIndexValue[i - 1]); float vCalc = voltage - uvIndexValue[i - 1]; UV += (1.0f / vRange) * vCalc - 1.0f; }
At first glance it looks like the value UV will even get bigger (UV+=something), but it turns out that always a negative number is added to UV.
(1.0f / vRange) * vCalc - 1.0f is always negative. So something is subtracted from the initial value UV.
It's a bit counter intuitive...I've seen other people's projects where they removed the fractional/decimal part from their code (unlike your code). Their sensors will therefore always be interpreted with a full 1 UV-index value too high.
*) Correct me if i'm wrong, but the example code calculates a UV-index with a one-decimal precision. But the value sent to the gateway, is sent in 2 decimals. Wouldn't it be enough to do:
send(msgUV.set(UVindex, 1));
Here are bits of my own code. I use the Arduino map() function to calculate the decimal for me.
Perhaps others find it easier to read too.:const int UV_threshold[12] = {50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170}; // in units of mV const float SAMPLE_TO_MV = (1.1*1000)/1024; // mV per sample-resolution uint16_t UV_index; // the UV index uint16_t UV_index_f; // the fractional part of the UV index ... // determine the UV index if (UV_value < UV_threshold[0]) { // too low value or // invalid value (sensor is wrongly connected? => always 0) UV_index = 0; UV_index_f = 0; } else { for (UV_index=11; UV_index>0; UV_index--) if (UV_value >= UV_threshold[UV_index]) break; // calculate fractional part of the UV-index if (UV_index == 11) { // already at the maximum level; // Displaying a fraction is meaningless UV_index_f = 0; } else { UV_index_f = map(UV_value, UV_threshold[UV_index],UV_threshold[UV_index+1], 0,9); // one decimal, so a number ranging 0 to 9 } } float UV_index_float = UV_index + (UV_index_f/10.0);
-
RE: Message is send twice
@esawyja In your last program, your battery level is only send when the generator changed state.
Probably you want to let the battery report it's level at regular intervals, independent of the generator state.
Boots33 pointed out how to know if a message has been sent succesfully.
Here is a version of your sketch that does both things:#define RETRY_TIMES 3 #define RETRY_WAIT 10000 #define BATTERY_REPORT_INTERVAL 60000 int oldValue; uint32_t battery_report_time; volatile bool generator_pin_changed = false; volatile int generator_pin_value; void generator_pin_interrupt_handler() { generator_pin_changed = true; generator_pin_value = digitalRead(GENERATOR_PIN); } void setup() { oldValue = digitalRead(GENERATOR_PIN); sendGeneratorMsg(oldValue==HIGH?0:1); battery_report_time = millis() + BATTERY_REPORT_INTERVAL; attachInterrupt(digitalPinToInterrupt(GENERATOR_PIN), generator_pin_interrupt_handler, CHANGE); } void loop() { int value = digitalRead(GENERATOR_PIN); if (value != oldValue) { oldValue = value; if (value == LOW) { Serial.println("Generator RUNNING - SENDING"); sendGeneratorMsg(1); } else { Serial.println("Generator NOT running - SENDING...."); sendGeneratorMsg(0); } } long sleep_time_left = battery_report_time - millis(); if (sleep_time_left < 0) { battery_report_time = millis() + BATTERY_REPORT_INTERVAL; sleep_time_left = BATTERY_REPORT_INTERVAL; read_batt(); } sleep(digitalPinToInterrupt(GENERATOR_PIN), CHANGE, sleep_time_left); } void sendGeneratorMsg(int state) { for (int i=0; i<RETRY_TIMES; i++) { if (send(msgGENERATOR.set(state))) { Serial.println("Generator message sent"); return; } wait(RETRY_WAIT); } Serial.println("Failed to send generator message"); } void read_batt() { wait(15000); int sensorValue = analogRead(BATTERY_SENSE_PIN); float batteryV = sensorValue * volt_value; send(batt_msg.set(batteryV,2)); }
EDIT: I have changed ^^the code^^ with the suggestions i made in my next post.
-
RE: Rebuild of my broken 433mhz Cresta/hideki UV-Sensor
I stripped the code to only include the UV measurement.
Hopefully it helps you out a bit.// Print debug information (test versions), (or not; in the final version) #define DEBUG_PRINT // print debug information when this line is uncommented (and the next line is commented) //#undef DEBUG_PRINT // (vice versa) //=================================================== // UVM30A ultraviolet detector. // The sensor's VCC is connected to +5V // // At first glance, the datasheet is not entirely making sense: // "输出电压" translates to "Output voltage", with a value of: DC 0—1V. // So the sensor will never output/measure the 2 highest values listed in the graph & table of the datasheet (1079 and 1170+). // The datasheet explains it: "(对应 UV 指数 0-10)" translates to "(corresponding to UV index 0-10)". Fair enough. // // "测试精度" translates to: "Test accuracy", with a value of: ±1 UV INDEX // That is not very accurate on a range 0-10. Example: if the real UV-index is 4, you could measure 3, or 5. // For that reason we take an average of multiple samples, to get a better measurement. // The sensor's (analog) output is connected to the Arduino Nano's at pin 14 (A0) #define UV_PIN 14 // The list of UV index thresholds (in mV). const int UV_threshold[12] = {50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170}; // in units of mV // The read value is a 10-bit value, ranging from 0 to 2^10-1 (0 to 1023). // The reference voltage on the input pin is set to 1.1V. // That voltage is spread out over the 1024 possible values of a sample. // So our achieved resolution equals (1.1 Volts / 1024) = 0.00107421875 Volt. // The UVM30A sensor datasheet lists all UV-index values according to measured milli-Volts. const float SAMPLE_TO_MV = (1.1*1000)/1024; // mV per sample-resolution uint16_t UV_value; uint16_t UV_index; // the UV index uint16_t UV_index_f; // the fractional part of the UV index // Compiler directives for averiging the UV-sensor readings // (Change the values of UV_AVERAGE_T & UV_AVERAGE_N according to your own taste). #define UV_AVERAGE_T 4000 // Sample interval duration in milliseconds.. (1 <= T <= 60000) #define UV_AVERAGE_N 10 // ..During that interval, N samples are taken, and averaged. (1 <= N <= 100, must be <>0) #if UV_AVERAGE_T < 1 // Sanity check. It must be dummy proof #define UV_AVERAGE_T 1 #endif #if UV_AVERAGE_N < 1 // Sanity check. It must be dummy proof #define UV_AVERAGE_N 1 // This value must be <>0 at all times, because we divide by it #endif // calculate once, use many times in the loop() const float UV_AVERAGE_N_RP = 1.0 / UV_AVERAGE_N; const uint32_t UV_AVERAGE_D = UV_AVERAGE_T * UV_AVERAGE_N_RP; //=================================================== //=================================================== // Process a UV measurement: // read an average value from the UV detector. // The average consists of N samples taken during a T milliseconds interval. //=================================================== void processUV() { // Set the reference voltage for sampling // For our ATmega328 Nano: INTERNAL = 1.1V, DEFAULT = 5V // After using analogReference(), the first few samples may not be accurate (according to the Arduino language reference), // and that is why we read a few dummy samples before starting the actual measurement. // NOTE: If you change the next statement, beware to adjust the value of SAMPLE_TO_MV too. analogReference(INTERNAL); for (int i=0; i<10; i++) UV_value = analogRead(UV_PIN); // ignore the possibly inaccurate samplevalues. #ifdef DEBUG_PRINT Serial.print("UV raw values: ["); #endif uint32_t average = 0; for (int i=0; i<UV_AVERAGE_N; i++) { #ifdef DEBUG_PRINT UV_value = analogRead(UV_PIN); Serial.print(UV_value); Serial.print(" "); average += UV_value; #else average += analogRead(UV_PIN); #endif delay(UV_AVERAGE_D); } UV_value = average * UV_AVERAGE_N_RP; #ifdef DEBUG_PRINT Serial.print("] avg: "); Serial.print(UV_value); #endif // We must convert sample-values into mV-values before we look up the UV-index. UV_value *= SAMPLE_TO_MV; #ifdef DEBUG_PRINT Serial.print(" mV: "); Serial.print(UV_value); #endif // determine the UV index if (UV_value < UV_threshold[0]) { // too low value or invalid value (in case the sensor is wrongly connected it always returns 0) UV_index = 0; UV_index_f = 0; } else { for (UV_index=11; UV_index>0; UV_index--) { if (UV_value >= UV_threshold[UV_index]) break; } // calculate fractional part of the UV-index if (UV_index == 11) { // already at the maximum level; Displaying a fraction is meaningless UV_index_f = 0; } else { UV_index_f = map(UV_value, UV_threshold[UV_index],UV_threshold[UV_index+1], 0,9); // one decimal, so a number ranging 0 to 9 } } float UV_index_float = UV_index + (UV_index_f*0.1); // that is the same as /10 #ifdef DEBUG_PRINT Serial.print(" UV index: "); Serial.println(UV_index_float); #endif } void setup() { // By default the Arduino sets all pins as input at startup, // so there is no need to explicitly set the pinMode pinMode(UV_PIN, INPUT); #ifdef DEBUG_PRINT // debug purposes Serial.begin(9600); #endif } void loop() { // UV measurement processUV(); // just some delay for (int i=0; i<5; i++) delay(1000); }
I edited my post.
The reason is that i'm using an Arduino Uno & Arduino Yún in my own project.
The Nano's pin numbering is quite different: pin named A0 is numbered 14.
If You copy/paste the code, and run it, it would look something like this:UV raw values: [351 353 339 343 349 349 334 346 338 347 ] avg: 344 mV: 369 UV index: 2.50 UV raw values: [344 344 344 348 343 341 349 346 345 349 ] avg: 345 mV: 370 UV index: 2.50 UV raw values: [348 345 309 343 342 346 315 346 343 346 ] avg: 338 mV: 363 UV index: 2.40 UV raw values: [330 317 343 340 343 343 341 338 342 341 ] avg: 337 mV: 362 UV index: 2.40 UV raw values: [338 337 312 337 335 335 336 299 342 338 ] avg: 330 mV: 354 UV index: 2.30
-
RE: Software I2C slave for Arduino Uno & TFT shield (+code)
Thanks gohan..
This forum is a great source of inspiration. Lots of examples of people and their own projects, and/or problems they encounter(ed).
I'm fairly new to MySensors & Arduino, but i have a lot of experience with Atmel AVR. At this time, i'm more reading than writing: absorbing info first. Hopefully i can help out others too sometimes.. it's cool to share knowledge.I already have 10 Arduino Yúns & 2 Raspberries at my disposal (they belong to friends i'm helping out).
It would be fun to find a sensible application to combine a MySensors radio network (or perhaps multiple networks), and the IOT-capabilities of the Yún(s) & Raspberries.
But that's another project.. -
RE: Help with irrigation LCD display
Hi markcaso,
I only had a quick look at your code. I do not claim that what i see is the cause of your problems. What i posted, is just something illogical in code (for me).
A suggestion to test if it is true what i've posted: comment out the few lines of code that i think are the cause of your problem.. like so:/* if (inSetup) { lcd.print(F(" Updating ")); lcd.setCursor(0, 1); lcd.print(F(" Valve Data: ")); lcd.print(valveIndex); } */
If you then see more info being displayed, you at least know that is the spot where things are getting messed up.
I can not run your code as easily as you do.. i only see code on a webpage. For you it's easy enough to try it out.About the non-initialized variables being used in code; Here's a shortened snippet of your code:
void updateDisplay() { static unsigned long lastUpdateTime; if (state != lastDisplayState || millis() - lastUpdateTime >= 3000UL) {
The very first time those lines are executed, who can say what value lastUpdateTime may have? One can assume that the value will be 0 (after powering on the MCU), but maybe there was already a value in that exact memorylocation while the chip got some kind of soft-reset. In that case, the program will behave differently. (meaning: it does not do what you expected).
It is better to assign values to variables before using them in code (i.e. comparing them with some specific value).
As an example: If lastUpdateTime would have a value of 0xFFFFFFFF (decimal 4294967295), one could have to wait a long time before (millis() - lastUpdateTime >= 3000UL) ! up to 49.7 days (using a calculator here, assuming millis()==0).I am a super newbee too. i spent a lot of time debugging my very first gateway & sensornode. (got it working today!!!). I know only about digital electronics (i mean: using it), and really really know very little about analog stuff. There are a lot of very good experts on electronics here on this forum. If we (try to) help eachother out, everybody makes progress and both will be successful.
Latest posts made by core_c
-
RE: Browser-based firmware generator
I am one of those few users that opened chrome://flags, and set:
Enable WebUSB support: disabled.
I already have installed a tool to program my Arduinos. I guess, it's the first thing most people install after aquiring an Arduino.
I also do not understand why i would ever use a cloud.
Perhaps i am "too oldskool".. using a browser to find what i search for, and (if it is code,) then download it.
When i want code, i do not care how i get it. Important is, that i can download it..
The bare product is what counts.. -
RE: Message is send twice
About your battery level send question, here's some explanation:
The intention is to let your node sleep when nothing happens.
Only when the generator pin changes, it interrupts the sleep cycle, and wakes up the node. It then checks the current generator pin state and sends the appropriate message. Then it goes to sleep again.
However, it does not sleep forever. At regular intervals the battery level is send. So every BATTERY_REPORT_INTERVAL milliseconds the current sleep cycle ends (because the timer has counted down and reached its end), and the battery level is send.
The program keeps doing this: Sleep, and wake up if the pin changed, and/or wake up when the battery level should be send. -
RE: Message is send twice
@esawyja i made the changes for you in my post made earlier^^
-
RE: Message is send twice
@esawyja attachInterrupt() should only be done once, in the setup() function.
-
RE: Message is send twice
@esawyja You are right. I made a mistake. This should fix it:
Change this line:uint32_t sleep_time_left = battery_report_time - millis();
into this:
long sleep_time_left = battery_report_time - millis();
A variable of type long can hold a negative number, but an unsigned long (same as uint32_t) can never hold a negative number (because it is unsigned, no sign, no minus sign, no negative).
So, if (sleep_time_left < 0) will never be true.. That was the mistake.I was also wondering if the generator would produce interrupts without using attachInterrupt().
Without that, you can still poll the generator pin, and see if the value changed (what is happening now), but the sleep() cycle would not be interrupted when the pin changed.
To be on the safe side, i would also add the following to your code:void setup() { attachInterrupt(digitalPinToInterrupt(GENERATOR_PIN), generator_pin_interrupt_handler, CHANGE); }
Hopefully that'll make it work as intended.
-
RE: Message is send twice
@esawyja In your last program, your battery level is only send when the generator changed state.
Probably you want to let the battery report it's level at regular intervals, independent of the generator state.
Boots33 pointed out how to know if a message has been sent succesfully.
Here is a version of your sketch that does both things:#define RETRY_TIMES 3 #define RETRY_WAIT 10000 #define BATTERY_REPORT_INTERVAL 60000 int oldValue; uint32_t battery_report_time; volatile bool generator_pin_changed = false; volatile int generator_pin_value; void generator_pin_interrupt_handler() { generator_pin_changed = true; generator_pin_value = digitalRead(GENERATOR_PIN); } void setup() { oldValue = digitalRead(GENERATOR_PIN); sendGeneratorMsg(oldValue==HIGH?0:1); battery_report_time = millis() + BATTERY_REPORT_INTERVAL; attachInterrupt(digitalPinToInterrupt(GENERATOR_PIN), generator_pin_interrupt_handler, CHANGE); } void loop() { int value = digitalRead(GENERATOR_PIN); if (value != oldValue) { oldValue = value; if (value == LOW) { Serial.println("Generator RUNNING - SENDING"); sendGeneratorMsg(1); } else { Serial.println("Generator NOT running - SENDING...."); sendGeneratorMsg(0); } } long sleep_time_left = battery_report_time - millis(); if (sleep_time_left < 0) { battery_report_time = millis() + BATTERY_REPORT_INTERVAL; sleep_time_left = BATTERY_REPORT_INTERVAL; read_batt(); } sleep(digitalPinToInterrupt(GENERATOR_PIN), CHANGE, sleep_time_left); } void sendGeneratorMsg(int state) { for (int i=0; i<RETRY_TIMES; i++) { if (send(msgGENERATOR.set(state))) { Serial.println("Generator message sent"); return; } wait(RETRY_WAIT); } Serial.println("Failed to send generator message"); } void read_batt() { wait(15000); int sensorValue = analogRead(BATTERY_SENSE_PIN); float batteryV = sensorValue * volt_value; send(batt_msg.set(batteryV,2)); }
EDIT: I have changed ^^the code^^ with the suggestions i made in my next post.
-
RE: Browser-based firmware generator
the word "Generator" scores.
i personally like "MyGenerator" most.. -
RE: Message is send twice
@esawyja No, it does not matter if it's active low or active high. I was only thinking that it could be an oversight.. something wrong in code that someone (possibly) keeps missing because they are assuming that that part of the code is correct.
About what you said previously: "looks like it detects the change, but does not do anything":
Correct me if i'm wrong, but this looks like it detects, and does something:interupt 1 5429 MCO:BGN:INIT OK,TSP=1 1 Generator NOT running - SENDING.... 5441 TSF:MSG:SEND,11-11-0-0,s=6,c=1,t=2,pt=2,l=2,sg=0,ft=0,st=OK:0
After that, when the generator did not change state anymore, you will see a stream of only sleep/wake-up messages (a stream, because sleeptime is 0). I see that stream start at 5648.
In your current program, i'm curious if that second send() is really needed (the last send in the "send,wait(10000),send" sequence).
But anyway, your skills got it working.. -
RE: Building a LED status
I know 0.00001 about Vera (i know just the name), but i probably can help you light up an RGB LED.
Can you post any code you already have running on an Arduino?
I know there is a S_RGB_LIGHT message in MySensors.. So i guess: it is also known/recognized by Vera.shoot!