Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #15594

    With a first Mini Ultra Pro 3 I made some tests with a 800 mAh LiPo battery and a solar panel and monitoring the battery voltage definitely shown the battery being charged.

    I then setup a production version using the same solar panel & the same battery but after a couple of weeks it’s now obvious that the battery is not charging while the solar panel is definitely getting a lot of sun. After triple checking the connections and the solders I initially thought there was a defect in the second mini ultra pro. After thinking about it I just realized that in test, I used delay() between the transmission while I’m using rtc.standbyMode(). Now I’m wondering if the mini ultra pro can charge the battery in standby mode.

    #15595
    LIM PHANG MOH
    Keymaster

    It will charge regardless of the mode as long as the input power is enough. Can I see what is in your code? And have you measured your board current consumption prior to testing under the sun?

    #15596

    I measured the board current and it’s around 15mA during the measuring time and 270µA in stand by mode. It’s running for 9 days now and on July 9th I measured vbatt at 4.01v and now it’s at 3.77v.

    The code follows. The only differences I remembered from the working version is the TEST_MODE which was activated first and no longer now. Another difference will be on pulling the unused pins as I’m pretty sure (I have to look up in my code history) I only included it lately.

    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <Adafruit_SleepyDog.h>
    
    #include <DHT.h>
    #include <DHT_U.h>
    
    #include <RTCZero.h>
    #include <SerialFlash.h>
    
    #include <RH_RF95.h>
    
    #define Serial SerialUSB
    #define LED_PIN 13
    // #define LED_PIN LED_BUILTIN
    
    #define ONE_WIRE_BUS 11
    // #define RC_PIN 5
    #define BATT_PIN A5
    #define VIN_PIN A4
    #define DHT_PIN 12
    
    // #define TEST_MODE
    #undef TEST_MODE
    
    #define RTC_SLEEP
    
    #ifdef TEST_MODE
    const unsigned long DELAY_SECS = 30; // 30 seconds
    const uint8_t RH_FROM = 2;
    #else
    const unsigned long DELAY_SECS = 60 * 5; // 5 minutes
    const uint8_t RH_FROM = 1;
    #endif
    
    const unsigned long DELAY_MILLIS = DELAY_SECS * 1000L;
    
    const uint8_t RH_TO = 10;
    
    RTCZero rtc;
    
    // Setup a oneWire instance to communicate with any OneWire devices
    OneWire oneWire(ONE_WIRE_BUS);
    // Pass our oneWire reference to Dallas Temperature sensor
    DallasTemperature sensors(&oneWire);
    
    // Setup dht sensor
    DHT_Unified dht(DHT_PIN, DHT11);
    
    static RH_RF95 rf95(5, 2); // Rocket Scream Mini Ultra Pro with the RFM95W
    
    const uint8_t HEADER_SIZE = 5;
    static uint8_t data[RH_RF95_MAX_MESSAGE_LEN];
    static uint8_t *payload = data + HEADER_SIZE;
    
    static uint8_t recv_buff[RH_RF95_MAX_MESSAGE_LEN];
    
    uint8_t msg_id = 0;
    
    void blink(uint16_t times, uint64_t d)
    {
        for (uint16_t i = times; i > 0; i--)
        {
            digitalWrite(LED_PIN, HIGH);
            delay(d);
            digitalWrite(LED_PIN, LOW);
            delay(d);
        }
    }
    
    void setup(void)
    {
    #pragma region Pullup unused pins into known state
        uint8_t pinNumber;
    
        pinMode(0, INPUT_PULLUP);
        pinMode(1, INPUT_PULLUP);
    
        // D7-D10
        for (pinNumber = 7; pinNumber <= 10; pinNumber++)
        {
            pinMode(pinNumber, INPUT_PULLUP);
        }
    
        pinMode(14, INPUT_PULLUP); // A0(D14)
        pinMode(15, INPUT_PULLUP); // A1(D15)
        pinMode(16, INPUT_PULLUP); // A2(D16)
        pinMode(17, INPUT_PULLUP); // A3(D17)
        pinMode(20, INPUT_PULLUP); // SDA(D20)
        pinMode(21, INPUT_PULLUP); // SCL(D21)
        pinMode(22, INPUT_PULLUP); // MISO(D22)
    
        // RX_LED (D25) & TX_LED (D26) (both LED not mounted on Mini Ultra Pro)
        pinMode(25, INPUT_PULLUP);
        pinMode(26, INPUT_PULLUP);
        // D30 (RX) & D31 (TX) of Serial
        pinMode(30, INPUT_PULLUP);
        pinMode(31, INPUT_PULLUP);
    
        // D34-D38 (EBDG Interface)
        for (pinNumber = 34; pinNumber <= 38; pinNumber++)
        {
            pinMode(pinNumber, INPUT_PULLUP);
        }
    #pragma endregion
    
        pinMode(LED_PIN, OUTPUT);
    
    #ifdef TEST_MODE
        Serial.begin(115200);
    
        while (!Serial && millis() < 20000)
        {
            // wait for serial port to connect. Needed for native USB port only
            blink(1, 200);
        }
    #endif
    
    #ifdef TEST_MODE
        Serial.println(F("Initializing serial flash"));
    #endif
        // Initialize serial flash
        SerialFlash.begin(4);
        // Put serial flash in sleep
        SerialFlash.sleep();
    
    #ifdef TEST_MODE
        Serial.println(F("Initializing RTC"));
    #endif
        // Initialize RTC
        rtc.begin();
    
    #ifdef TEST_MODE
        Serial.print(F("RTC on startup "));
        print_datetime();
        Serial.println();
    #endif
    
    #ifdef TEST_MODE
        Serial.println(F("Initializing onewire sensors"));
    #endif
        sensors.begin();
        sensors.setResolution(12);
    
    #ifdef TEST_MODE
        Serial.println(F("Initializing DHT"));
    #endif
        dht.begin();
    
    #ifdef TEST_MODE
        Serial.println(F("Initializing radio"));
    #endif
        if (!rf95.init())
        {
            blink(20, 333);
    #ifdef TEST_MODE
            Serial.println(F("Radio init failed"));
    #endif
        }
    
        rf95.setFrequency(868.0);
        rf95.setTxPower(13, false);
    
    #ifdef TEST_MODE
        Serial.println(F("Waiting before start"));
    #endif
    
        blink(5, 1000);
    
    #ifdef TEST_MODE
        Serial.println(F("Starting"));
    
        sensor_t dht_sensor;
        dht.temperature().getSensor(&dht_sensor);
        Serial.println(F("------------------------------------"));
        Serial.println(F("Temperature Sensor"));
        Serial.print(F("Sensor Type: "));
        Serial.println(dht_sensor.name);
        Serial.print(F("Driver Ver:  "));
        Serial.println(dht_sensor.version);
        Serial.print(F("Unique ID:   "));
        Serial.println(dht_sensor.sensor_id);
        Serial.print(F("Max Value:   "));
        Serial.print(dht_sensor.max_value);
        Serial.println(F("°C"));
        Serial.print(F("Min Value:   "));
        Serial.print(dht_sensor.min_value);
        Serial.println(F("°C"));
        Serial.print(F("Resolution:  "));
        Serial.print(dht_sensor.resolution);
        Serial.println(F("°C"));
        Serial.println(F("------------------------------------"));
        // Print humidity sensor details.
        dht.humidity().getSensor(&dht_sensor);
        Serial.println(F("Humidity Sensor"));
        Serial.print(F("Sensor Type: "));
        Serial.println(dht_sensor.name);
        Serial.print(F("Driver Ver:  "));
        Serial.println(dht_sensor.version);
        Serial.print(F("Unique ID:   "));
        Serial.println(dht_sensor.sensor_id);
        Serial.print(F("Max Value:   "));
        Serial.print(dht_sensor.max_value);
        Serial.println(F("%"));
        Serial.print(F("Min Value:   "));
        Serial.print(dht_sensor.min_value);
        Serial.println(F("%"));
        Serial.print(F("Resolution:  "));
        Serial.print(dht_sensor.resolution);
        Serial.println(F("%"));
        Serial.print(F("min_delay:  "));
        Serial.print(dht_sensor.min_delay);
        Serial.println(F("ns"));
        Serial.println(F("------------------------------------"));
    #endif
    
        // Set RTC from server
        sendCommand(0x00, 0, &setRtcCallback);
    }
    
    void sendCommand(uint8_t opCode, uint8_t payloadSize, void (*callback)(uint8_t, int16_t, uint8_t, uint32_t, uint32_t))
    {
    #pragma region Headers
        // Fill application headers
        uint32_t now = rtc.getEpoch();
        uint8_t *buffer = data;
    
        // Op code: 0x00 ping, 0x01 send sensor data
        *(buffer++) = opCode;
    
        // My time stamp
        *(buffer++) = now >> 24;
        *(buffer++) = now >> 16;
        *(buffer++) = now >> 8;
        *(buffer++) = now;
    
    #ifdef TEST_MODE
        if (buffer != payload)
        {
            Serial.print(F("Inconsistency between header and payload "));
            Serial.print(buffer - data);
            Serial.print(F("/"));
            Serial.println(payload - data);
        }
    #endif
    #pragma endregion
    
        uint8_t data_size = HEADER_SIZE + payloadSize;
    
        rf95.setHeaderFrom(RH_FROM);
        rf95.setHeaderTo(RH_TO);
        rf95.setHeaderId(msg_id++);
    
    #ifdef TEST_MODE
        Serial.print(F("About to send "));
        Serial.print(data_size);
        Serial.print(F(" bytes of data to "));
        Serial.print(rf95.headerTo());
        Serial.print(F(" with id "));
        Serial.println(rf95.headerId());
    #endif
    
        digitalWrite(LED_PIN, HIGH);
        rf95.send(data, data_size);
        rf95.waitPacketSent();
        digitalWrite(LED_PIN, LOW);
    
        // Now wait for a reply
        uint8_t len = sizeof(recv_buff);
    
        if (rf95.waitAvailableTimeout(3000))
        {
            digitalWrite(LED_PIN, HIGH);
            // Should be a reply message for us now
            if (rf95.recv(recv_buff, &len))
            {
                int16_t rssi = rf95.lastRssi();
                uint8_t from = rf95.headerFrom();
    #ifdef TEST_MODE
                Serial.print(F("got reply from "));
                Serial.print(from, DEC);
                Serial.print(F(" RSSI: "));
                Serial.println(rssi, DEC);
    #endif
                uint8_t *b = recv_buff;
                uint8_t status = *(b++);
                if (status == 0x00 && len >= 10)
                {
                    if (callback != NULL)
                    {
                        uint8_t in_reply_to = *(b++);
                        uint32_t my_ts = *(b++) << 24 | *(b++) << 16 | *(b++) << 8 | *(b++);
                        uint32_t server_ts = *(b++) << 24 | *(b++) << 16 | *(b++) << 8 | *(b++);
    
                        callback(from, rssi, in_reply_to, my_ts, server_ts);
                    }
                }
    #ifdef TEST_MODE
                else
                {
                    Serial.print(F("Unexpected status "));
                    Serial.print(status);
                    Serial.print(F(" or incorrect length "));
                    Serial.print(len);
                }
    #endif
            }
    #ifdef TEST_MODE
            else
            {
                Serial.println(F("recv failed"));
            }
    #endif
            digitalWrite(LED_PIN, LOW);
        }
    #ifdef TEST_MODE
        else
        {
            Serial.println(F("No reply, is rf95_server running?"));
        }
    #endif
    }
    
    void setRtcCallback(uint8_t from, int16_t rssi, uint8_t in_reply_to, uint32_t my_ts, uint32_t server_ts)
    {
    #ifdef TEST_MODE
        Serial.print(F("Setting rtc to "));
        Serial.println(server_ts);
    #endif
        rtc.setEpoch(server_ts);
    }
    
    float readBatteryVoltage(uint8_t pin, float factor)
    {
        uint32_t adcReading = analogRead(pin);
        // Discard inaccurate 1st reading
        adcReading = 0;
        // Perform averaging
        for (int counter = 10; counter > 0; counter--)
        {
            adcReading += analogRead(pin);
        }
        adcReading = adcReading / 10;
    
        return adcReading * (factor / 1023.0);
    }
    
    uint8_t *packFloat(uint8_t *buffer, float value)
    {
        int int_value = value * 100;
        *(buffer++) = int_value >> 8;
        *(buffer++) = int_value;
        return buffer;
    }
    
    void loop(void)
    {
        digitalWrite(LED_PIN, HIGH);
    
    #pragma region Measuring
        Serial.println(F("Measuring pool temperature"));
        sensors.requestTemperatures();
        float pool_temp = sensors.getTempCByIndex(0);
    
    #ifdef TEST_MODE
        Serial.println(F("Measuring battery"));
    #endif
    
        float batt_volts = readBatteryVoltage(BATT_PIN, 4.3);
        float vin_volts = readBatteryVoltage(VIN_PIN, 6.6);
    
        float my_temp = 0.0;
    
        sensors_event_t event;
        dht.temperature().getEvent(&event);
        if (isnan(event.temperature))
        {
            Serial.println(F("Error reading temperature!"));
        }
        else
        {
            my_temp = event.temperature;
        }
    
        float my_humidity = 0.0;
        // Get humidity event and print its value.
        dht.humidity().getEvent(&event);
        if (isnan(event.relative_humidity))
        {
            Serial.println(F("Error reading humidity!"));
        }
        else
        {
            my_humidity = event.relative_humidity;
        }
    
        uint32_t now = rtc.getEpoch();
    
    #ifdef TEST_MODE
        Serial.print(F("Report at "));
        Serial.println(now);
        Serial.print(F("Pool temperature: "));
        Serial.print(pool_temp);
        Serial.println(F("°C"));
    
        Serial.print(F("Inner temperature: "));
        Serial.print(my_temp);
        Serial.println(F("°C"));
    
        Serial.print(F("Inner humidity: "));
        Serial.print(my_humidity);
        Serial.println(F("%"));
    
        Serial.print(F("Battery: "));
        Serial.print(batt_volts);
        Serial.println(F("v"));
    
        Serial.print(F("VIN: "));
        Serial.print(vin_volts);
        Serial.println(F("v"));
    
    #endif
        digitalWrite(LED_PIN, LOW);
    
    #pragma endregion
    
        uint8_t *buffer = payload;
    
        buffer = packFloat(buffer, pool_temp);
        buffer = packFloat(buffer, my_temp);
        buffer = packFloat(buffer, batt_volts);
        buffer = packFloat(buffer, vin_volts);
        buffer = packFloat(buffer, my_humidity);
    
        int payload_size = buffer - payload;
    
        sendCommand(0x01, payload_size, NULL);
    
    #ifdef TEST_MODE
        Serial.print(F("Sleeping for "));
        Serial.print(DELAY_SECS);
        Serial.println(F("s"));
    
        Serial.flush();
    #endif
    
        rf95.sleep();
    
    #ifdef RTC_SLEEP
        rtc.setAlarmEpoch(rtc.getEpoch() + DELAY_SECS);
        rtc.enableAlarm(rtc.MATCH_YYMMDDHHMMSS);
        rtc.attachInterrupt(alarmMatch);
    
        // USB port consumes extra current
        USBDevice.detach();
        // Enter sleep mode
        rtc.standbyMode();
    
    #ifdef TEST_MODE
        // Reinitialize USB for debugging
        USBDevice.init();
        USBDevice.attach();
        blink(10, 125);
    #endif
    #else
        delay(DELAY_MILLIS);
    #endif
    
        // Wakeup radio
        rf95.setModeIdle();
    
    #ifdef TEST_MODE
        Serial.print(F("Woke up "));
        print_datetime();
        Serial.println();
    #endif
    }
    
    void alarmMatch()
    {
    }
    
    void print_datetime()
    {
        Serial.print(F("20"));
        print2digits(rtc.getYear());
        Serial.print(F("-"));
        print2digits(rtc.getMonth());
        Serial.print(F("-"));
        print2digits(rtc.getDay());
        Serial.print(F(" "));
        print2digits(rtc.getHours());
        Serial.print(F(" "));
        print2digits(rtc.getMinutes());
        Serial.print(F(" "));
        print2digits(rtc.getSeconds());
    }
    
    void print2digits(int number)
    {
        if (number < 10)
        {
            Serial.print(F("0")); // print a 0 before if the number is < than 10
        }
        Serial.print(number);
    }
    #15598
    LIM PHANG MOH
    Keymaster

    If the red LED labelled CHG and green LED labelled PG is lit when either external power applied on USB or VIN, it means the battery is being charged.

    There’s a lot going on your code, but how are you powering the DHT sensors? A dedicated power supply line to it? Anyhow, it needs to be switched off.

    #15599

    I use the 3.3v line to power the DHT 11 & the DSC18B20. I know i should add a switch to turn down those sensors. however it’ll increase the complexity of the board and the code and I figured the current consumption in standby mode combined with the solar panel would be good enough to have the whole thing work from late spring to early fall (this is a pool sensor so I definitely do not need it in winter).

    Since you didn’t see anything obvious in the code that would explain why the battery is not charging I’m going to switch the mini ultra and see if it changes anything

    #15600
    LIM PHANG MOH
    Keymaster

    If the red LED labelled CHG and green LED labelled PG is lit when either external power applied on USB or VIN, it means the battery is being charged.

    Is both LED lit up?

    You could just use a pin to power up each sensor VCC as they consumes less than few mA per sensor.
    For a current project I have, I use a proper MOSFET to cut off the power to the sensors.

    #15601

    Nope only PG is lit. On startup, I have both leds flashing but that does not last and really soon, CHG goes down and only PG is lit up. Also I notice that connecting the solar panel to vin does not do anything and the startup occurs only when I connect the battery. Is it an expected behaviour? Anyway, since, switching the mini ultra pro didn’t change anything to the battery charge I’m going to restart from ground up with a minimal program and only the battery and panel connected. Problem: I don’t have any spare battery ore panel so I have to order a battery and I’ll emulate the panel with a generator.

    #15602
    LIM PHANG MOH
    Keymaster

    When you connect the USB port and a battery does the CHG LED lit up? It should.
    I tested every single unit for charging with a battery and also ensure voltages goes up accordingly.

    #15603

    When you connect the USB port and a battery does the CHG LED lit up?

    Yes when I connect a battery and the USB port, both PG & CHG leds are on and the battery seems to be charging. Next step: try with VIN

Viewing 9 posts - 1 through 9 (of 9 total)
  • You must be logged in to reply to this topic.