Which microcontroller to controll leds with timer

My mother bought some deco stones with LED ligths. The problem is this deco-stones were not water proof so the internal componets got damaged and I would like to replace them. Now is the question how can I do that best. I just got an led strip where i can use the LEDs. But now the more difficult part comes the stones are powered by batterie and they should have one of these two behaviors:
1.Turn the LEDs on for 6 hours and then for 18 hours off
2. Only turn the leds on if it is dark (use of a photo resistor?)

After searching in the internet i came across the ATTINY 13A-PU. It seems this controller has a low power consumption and could be able to do the timer thing.
( I rode that it has an 8bit timer which means that it can hold 255 Secounds so i have to use that timer again and again until i get my 6 or 18 hours)

Are there better microcontrollers for this job? Or would I use the ATTINY 13A-PU correct?

Can i power leds with the Pins of the ATTINY 13A-PU or should i not connect them directly? (Using a transistor or mosfet)
The LEDs are SMD 3528 5V.

Since the rocks have different sizes I would like to connect from 2-8 LEDs (depending how bright the rocks should be.

Could You try and figure out the original components and wiring? I feel the original circuitry was someting like a bttery (CR2032?), an LED and a resistor. Why complicate things by trying to put LED strips and a controller into it? Some photos could help.

Yeah i tryed that first but I didn´t find anything googeling the pcb or the the String on the parts.
PCB: HTX-5730
Part 1:sk618
Part 2: 2TI
Then there is an resistor and 2 Parts were i am not 100% sure about them but I think, the the one could be a diode and the other an capacitor. I currently can not make photos I will try to get some tomorrow. Alot of the PCB got a waterdamage . The resistor of one PCB even corroded.

Sorry I forgot to mention that the thing was powerd by 3 AA 1,5V batteries not a small CR2032.

I am cutting the leds from the ledstrip (they are rated waterproof and I only have to connect them to the powersource. They work with no additional parts needed and they were cheaper to buy as ledstrip as when I would buy the same amount as ledparts)

How many leds total? Driving from any ATtiny, ATmega, ESP, .... isn't possible direct from the pins. one led is 20mA and that is close near the max output or sink possibility of a µC. You must use a MOSFET (like IRLZ44) or transistor capable to drive the whole current.

ATtiny + DS3231 (+ coin cell) and MOSFET can do the job.

This is the old pcb:


Is there a way to see how they wire the components? (Desolving the layer over the PCB?)

Do I really need an extra coin cell? Can I not use the the 3x AA batteries for that since the ATtiny can handle up to 5,5V?

The LED count would be between 2-6 LEDs depending on the size of the deco-stone

In this project they connected 4 LEDs directly to the microcontroller. Why can they do it there? ATtiny13 - IR remote to control LEDs (NEC proto) - Łukasz Podkalicki
Or does it just put a higher wear on the microcontroller so that it gets damaged after some time passed?

The coin cell prevent the DS3231 to loose the date and time if the power fails.

Screen Shot 12-23-22 at 12.59 PM

edit: the metal cylinder is likely a horloge crystal 32.768kHz.

So the microcontroller has an extra input for a coin cell?

But if I understand it right the DS3231N is used together with an arduino or an other microcontroller? Or can you use it on its own too?

The easiest way is to use an ARduino UNO and a DS1307 RTC.

The datasheet shows specs for Vbatt ranging up to 5.5 volts, so there is no electrical reason you can't use the three AAs.

But practically, you've signed up to lose the time of day when you change out the batteries.

You could solve that with a largish capacitor and a promise to be quick about changing the batteries. It seems more convenient just to use the existing battery holder and plot a CR2032 or whatever on in there.

a7

Ah ok is it usable with other microcontrollers too like the ATTiny? (ESP32 should not be a problem either?)

I am trying to make it a efficient as possible sp I try to only use one controller. Or is it possible to reduce the current consumtion when I used bout controllers?

Yeah thats true, but actually if the timing gets lost it is no big problem since the the old ones did not keep the data too.

If I would use the coin cell how long can I expect that it would run with out chaniging the batterie?

I was thinking of maybe giving that thing an IR receiver so I could set the start time and how long it should turn the Leds on.remotely. Does that make sense?

I think I will ask my mother what she preferes ^^. I guesss it will only used during christmas time but I am not really sure. That would mean that the time reset problem would not be a big issue.

When I use the coin cell are there thinkgs which I have to be aware about?

Should I build an temperature fuse in to the circuit or is it not really usable.

Many thanks for the help I alreday got from you guys

You can try ATTtiny. But those have lower number of I/O pins. Flash memory is also smaller. I don't think you'll get a smooth performance.

I would use a "new" ATTiny - probably ATTiny212. For this you need crystal precision timing and ATTiny13 does not have a crystal oscillator.

The funny thing is that I already looked in to that controller because it has more flash and ram as the attiny13 and I could get it cheaper for some reason.
The only problem is that it seems the it is sold out on the big distributors. Is there a difference between the ATTINY202-SSF and the ATTINY202-SSNR because there are still enough in stock.

The ATTiny202 does not have a crystal oscillator. You don't need super precise timing for this but still:
If you tolerate drift of half hour in a month that is one minute per day. That is 1/(24*60) ~ 690 ppm ~ 0.07 %. Easy to reach with any crystal but impossible with a common RC oscillator.
Of course you can add an external RTC but this is a bit complicated workaround.

when I use an crystal oscillator would that change something in the code (special instructions) or would I still use millis but it would be more precise?

The setting of the execution time should work either with an infrared remote or a bluetooth module (the same would be possible for the syncing).
I am currently preparing to build prototypes of bouth versions an the compare which one works better. But the is not an continues bluetooths communication, only a very limited communication to ask for new commands (On/Off) or new settings.

Is there a reason why the Attiny13 is more expensive as the Attiny 202 or the 212?

You may use the RTC counter clocked from the watch crystal for this with the CPU in sleep and generating periodic wake-ups. I don't know if there is some Arduino support for this.

Another option is to use the watch crystal for clocking the whole MCU. This will need more current (but I expect it will still be a few microamps). Everything will be slooow (probably not a problem for this application unless you want to use some PWM dimming), you probably can use the Arduino functions if you find a way to tell Arduino which frequency is used. It should be possible but I don't know how to do it. However I am not sure if everything will work as expected with such slow clock.

The last option is to use some "fast crystal" like 1 MHz or so. There shouldn't be much issues but power consumption will be in order of milliamps even with ligths off. OTOH an always-on BT receiver or iR receiver will probably consume similar current.

I believe it is because ATTiny202 uses newer, smaller process and so much more features fits into smaller area of silicon. ATTiny13 is an old, obsolete device and you pay for the fact they still bother to manufacture and sell it. It probably has no advantage over the new ATTinies - except for simplicity.

This is my current code which I am using for that(the main file is just for testing at the moment):

#include <Arduino.h>
#include "SimpleTimer.h"
// #define DEBUGGING

SimpleTimer timer;

// Pin to switch the device on and off
int8_t outputPin = 2;
int8_t currenState = LOW;

int8_t getNextState()
{
    currenState = currenState == HIGH ? LOW : HIGH;
    return currenState;
}

void testAddAlerts()
{
    timer.addAlert(00, 00, 05, B01111111);
    timer.setAllAlertsActive(true);
}

void setup()
{

#ifdef DEBUGGING
    Serial.begin(115200);
#endif

    pinMode(outputPin, OUTPUT);
    testAddAlerts();
    timer.setTimer(0, 0, 0);
    digitalWrite(outputPin, getNextState() );
    unsigned long future = millis() + 2000;
    while (future > millis())
    {
        delay(100);
    }
    digitalWrite(outputPin, getNextState());
}

void loop()
{

    if (timer.update() == 1)
    {
        // Serial.println("Alert");

        digitalWrite(outputPin, getNextState());
        // Resets the timer so there is an output every alert
        timer.setTimer(0,0,0);
        timer.setAllAlertsActive(true);
    }
}

And the classes used for it :

#include <Arduino.h>
#pragma once
// #define CHECKONLYEVERYSECOND
// #define DEBUGGING

struct Alert
{
    Alert(int32_t time,  uint8_t executionDays)
    {
        executionTime = time;
        setExecutionDays(executionDays);
        activate(true);
    }
    /**
     * @brief Set the execution time
     *
     * @param time
     */
    void setExecutionTime(uint32_t time)
    {
        executionTime = time;
    }

    uint8_t getExecutionDays()
    {
        return data >= 128 ? data - 128 : data;
    }

    void setExecutionDays(uint8_t bitmask)
    {
        boolean active = isActive();
        data = bitmask;
        activate(active);
    }
    /**
     * @brief Activates or deactivates the alert
     *
     * @param activate
     */
    void activate(bool activate)
    {
        if (isActive())
        {
            if (!activate)
            {
                data -= 128;
            }
        }
        else
        {
            if (activate)
            {
                data += 128;
            }
        }
    }
    /**
     * @brief Returns if the alert is currently active or not
     *
     * @return true The alert is active
     * @return false The alert is deactivated
     */
    bool isActive()
    {
        if (data >= 128)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    Alert *nextAlert = nullptr;
    /**
     * @brief data saves multiple differnt data in an 8 bit integer
     * The first bit indcates if the alert is active
     *
     *
     */
    uint8_t data;
    uint32_t executionTime = 0;
};

/**
 * @brief Keeps track of time and triggers when an alert occures
 * (Use the update function for that)
 *
 */
class SimpleTimer
{

public:
    SimpleTimer();
    ~SimpleTimer();
    /**
     * @brief Updates the time with the elapsed time and checks if an alert is triggered. Also it resets the time and the alerts when "a day" is passed.
     *
     * @return returns 1 if an alert was triggered and 0 if noting happend
     */
    int update();

    /**
     * @brief Converts the time given as normal time like 18:30:30 in milliseconds
     *
     * @param hours A value between 0-23
     * @param minutes A value between 0-59
     * @param seconds A value between 0-59
     * @return The time in milliseconds
     */
    uint32_t convertTimeToMilliSec( uint8_t hours,  uint8_t minutes,  uint8_t seconds);

    /**
     * @brief Adds an alert to the timer
     *
     * @param time The time when the alert should trigger
     */
    void addAlert(uint32_t time,  uint8_t weekdays);

    /**
     * @brief Adds an alert to the timer
     *
     * @param hours A value between 0-23
     * @param minutes A value between 0-59
     * @param seconds A value between 0-59
     */
    void addAlert( uint8_t hours,  uint8_t minutes,  uint8_t seconds,  uint8_t weekdays);

    /**
     * @brief Remove the alert on the given index
     *
     * @param index the position of the alert
     * @return boolean which indicates if the removing was succesfull
     */
    boolean removeAlert(int index);

    /**
     * @brief Remove the alert with the time
     *
     * @param time the time which should get removed
     * @return boolean which indicates if the removing was succesfull
     */
    boolean removeAlert(uint32_t time);

    /**
     * @brief Get the alert with the given index
     *
     * @param index An positive integer which is the desired index of the alert
     * @return Returns an Alert if it exists. If there is no Alert on this index it returns nullptr.
     */
    Alert *getAlert( uint8_t index);

    /**
     * @brief Sets all alerts inactive or active ´
     *
     * @param active Value which defines if all alerts should be active or inactive
     */
    void setAllAlertsActive(bool active);

    /**
     * @brief Sets the current time
     *
     * @param hours A value between 0-23
     * @param minutes A value between 0-59
     * @param seconds A value between 0-59
     */
    void setTimer( uint8_t hours,  uint8_t minutes,  uint8_t seconds);

    // Used for debugging
    void printTime(uint32_t time)
    {
#ifdef DEBUGGING
        // Uses too mutch resources so it will only used to debug
        int hours = time / (1000 * 60 * 60);
        time = time - hours * (1000 * 60 * 60);
        int minutes = time / (1000 * 60);
        time = time - minutes * (1000 * 60);
        int seconds = time / 1000;
        time = time - seconds * 1000;
        Serial.print(hours);
        Serial.print(":");
        Serial.print(minutes);
        Serial.print(":");
        Serial.print(seconds);
        Serial.print(":");
        Serial.println(time);
#endif
    }

protected:
    uint32_t lastTimeUpdate = 0;
    /**
     * @brief Represents the current daytime in milliseconds if it synced before, else it is just a virtual day with 24h
     *
     */
    uint32_t time = 0;
    /**
     * @brief Saves all alerts
     *
     */
    Alert *rootAlert = nullptr;
    // Saves the current time just here so the microncontroller does not need to reserve always new storage
    uint32_t currentTime;

#ifdef CHECKONLYEVERYSECOND
    /**
     * @brief Stores the milliseconds elapesed since the last full second was reached
     * Only use when CHECKONLYEVERYSECOND is defined
     *
     */
    int16_t lastSecUpdate;
#endif
};
#include "SimpleTimer.h"

SimpleTimer::SimpleTimer()
{
    time = 0;
}

SimpleTimer::~SimpleTimer()
{
}

uint32_t SimpleTimer::convertTimeToMilliSec(uint8_t hours, uint8_t minutes, uint8_t seconds)
{
    return ((((hours * 60) + minutes) * 60) + seconds) * 1000;
}

void SimpleTimer::setTimer(uint8_t hours, uint8_t minutes, uint8_t seconds)
{
    // TODO check if params are valid not negativ or to high
    // Calculates the time in milli seconds
    time = convertTimeToMilliSec(hours, minutes, seconds);
}

void SimpleTimer::setAllAlertsActive(bool activ)
{
    Alert *currentAlert = rootAlert;
    while (currentAlert != nullptr)
    {
        currentAlert->activate(activ);
        currentAlert = currentAlert->nextAlert;
    }
}

void SimpleTimer::addAlert(uint8_t hours, uint8_t minutes, uint8_t seconds, uint8_t weekdays)
{
    addAlert(convertTimeToMilliSec(hours, minutes, seconds), weekdays);
}

void SimpleTimer::addAlert(uint32_t time, uint8_t weekdays)
{
    if (rootAlert != nullptr)
    {
        Alert *currentAlert = rootAlert;
        while (currentAlert->nextAlert != nullptr)
        {
            currentAlert = currentAlert->nextAlert;
        }

        currentAlert->nextAlert = new Alert(time, weekdays);
        currentAlert->nextAlert->activate(true);
    }
    else
    {
        rootAlert = new Alert(time, weekdays);
    }
}

int SimpleTimer::update()
{
    uint8_t returnValue = 0;
    currentTime = millis();
    time += currentTime - lastTimeUpdate;

#ifdef CHECKONLYEVERYSECOND
    lastSecUpdate += currentTime - lastTimeUpdate;
    if (lastSecUpdate >= 1000)
    {
        printTime(time);
        lastSecUpdate = lastSecUpdate - 1000;
#endif
        if (rootAlert != nullptr)
        {
            Alert *currentAlert = rootAlert;
            while (currentAlert != nullptr)
            {
                if (currentAlert->isActive() && currentAlert->executionTime <= time)
                {
                    currentAlert->activate(false);
                    returnValue = 1;
                }
                else
                {
                    currentAlert = currentAlert->nextAlert;
                }
            }
        }
        // Test if "a day" has passed
        if (time >= 86400000)
        {
            time = time - 86400000;
            setAllAlertsActive(true);
        }
#ifdef CHECKONLYEVERYSECOND
    }
#endif
    lastTimeUpdate = currentTime;
    return returnValue;
}

Alert *SimpleTimer::getAlert(uint8_t index)
{
    if (index < 0)
    {
        return nullptr;
    }
    Alert *askedAlert = rootAlert;
    for (int i = 0; i <= index; i++)
    {

        if (index == i)
        {
            return askedAlert;
        }
        if (askedAlert->nextAlert != nullptr)
        {
            askedAlert = askedAlert->nextAlert;
        }
        else
        {
            return nullptr;
        }
    }
    return askedAlert;
}

The odd thing is that the code works with the esp32S2 but with the attiny202 it just turns the LED on and of which happens in the setup but not in the loop.
Is there a possibility, that the RAM is not enough for it so it just does nothing?
If it would work,it should turn the LED for 5 sec on and then turn it off for 5 sec. (And then repeat that)

Do you mean I should use the RTC counter as Interrupt to wake the controller to check if it has to do something?