logo elektroda
logo elektroda
X
logo elektroda
Dostępna jest polska wersja

Czy wolisz polską wersję strony elektroda?

Nie, dziękuję Przekieruj mnie tam

How to Implement a Clock in OpenBeken Devices Without Using NTP Protocol

max4elektroda 6639 97
Best answers

How can I add a clock to OpenBeken devices that keeps time locally without relying on NTP, while staying compatible across platforms?

Implement it as a separate optional clock subsystem, not as NTP itself: split the generic time helpers out of the NTP driver, rename APIs to `Clock_*`, and gate the feature with a disabled-by-default `ENABLE_LOCAL_CLOCK` in `obk_config.h` so existing builds and devices are unaffected [#21031682][#21032115] Use a companion `ENABLE_LOCAL_CLOCK_ADVANCED` for DST/timezone handling if needed [#21032907] For timekeeping, base the clock on a more accurate uptime source from RTOS ticks rather than a simple `g_secondsElapsed++`, because the counter can drift and it should not be moved backward at runtime or driver logic may break [#21639787][#21639876] If you need an initial time source without NTP, the clock can be set from the browser or by an HTTP request from another device, then continue running locally [#21038303]
Generated by the language model.
ADVERTISEMENT
  • #61 21634968
    p.kaczmarek2
    Moderator Smart Home
    @insmod what do you think? Should we merge it, and if so, at which stage?
    Helpful post? Buy me a coffee.
  • ADVERTISEMENT
  • #62 21634973
    insmod
    Level 31  
    >>21634968
    Which one? If #1729, then it lgtm, and i think that #1727 can be merged too.
    DS3231 and driver start failure probably better it they are in separate prs.
  • ADVERTISEMENT
  • #63 21634977
    p.kaczmarek2
    Moderator Smart Home
    I'm a bit worried about flash size, if we keep merging features that are used rarely we will run into more issues like OTA ovewriting LFS soon. Still, maybe we can indeed merge clock stuff now and try to make up for it, we still have long strings in the code, even the flag descriptions, they are super long. Maybe we should edit flags page to fetch flash descriptions from Github.
    Helpful post? Buy me a coffee.
  • #64 21634978
    insmod
    Level 31  
    Well, it was reported that bk ota binaries are about 6kb lighter.

    Added after 1 [hours] 15 [minutes]:

    tr6260 size increase is probably because ntp is required(?), and so it wasn't disabled.
    There is a wpa_get_ntp_timestamp function and a separate sntp_tr component.
  • #65 21635354
    max4elektroda
    Level 24  
    Let's agree on some final tests, I'm busy this weekend but can spare some time next week.
    One thing I just saw: I changed the call to set DST, I'll have to change it back to the actual command or add an alias for actual call.
    I can also, like it's done for tasmota, compile a list with all possible calls per timezone for our approach (like this one https://tasmota.github.io/docs/Timezone-Table/ )
  • #66 21638397
    max4elektroda
    Level 24  
    Changed to allow compatibility CMD.
    Now, what would we need to test?
    I would propose

    Start NTP
    set TZ
    Set DST
    Test DST changes
    Set latitude and longitude and check sunrise and sunset

    Anything else?

    Did a first try for DCF77 decoder, tested working on W800 and ESP32.
    Problem is it's using a very slow code one bit per second.
    Actually I use interrupts, but it needs both edges to detect length of the "bit", so e.g. Beken is out.
    Can I start an own task testing level of an GPIO pin e.g every 10ms as a driver?
    The requirements are not particularly strict; it is sufficient to distinguish 100ms and 200ms pulses and almost 2 seconds without pulse.
  • #67 21638403
    insmod
    Level 31  
    >>21638397
    For beken, did you try change edge directly in interrupt? E.g. gpio_int_enable to opposite edge.
    I think i'll eventually write a separate HAL for interrupts.
  • #68 21638410
    max4elektroda
    Level 24  
    insmod wrote:
    >>21638397
    For beken, did you try change edge directly in interrupt? E.g. gpio_int_enable to opposite edge.
    I think i'll eventually write a separate HAL for interrupts.

    No, but I'll try that. Thanks!
  • #69 21638411
    p.kaczmarek2
    Moderator Smart Home
    Give it a try. We also have gpio_int_enable source, btw:
    https://github.com/openshwprojects/OpenBK7231...t/bk7231t_os/beken378/driver/gpio/gpio.c#L536
    Maybe some nested calls could be omitted for speed?
    Code: C / C++
    Log in, to see the code
    Helpful post? Buy me a coffee.
  • #70 21638498
    max4elektroda
    Level 24  
    insmod wrote:
    I think i'll eventually write a separate HAL for interrupts.

    That would really be a big step to simplify some code. Thinking of BL0937 driver and it's interrupt code actually needing 1:1 code and ifdefs ;-)
  • #71 21638663
    p.kaczmarek2
    Moderator Smart Home
    I've did basic OTA separation and I could try interrupt HAL cleanup as well, but I am a bit limited by testing. I can try making PR and leave it for @divadiow to test. Altough.... if I do it, maybe I can do also "Counter" pin role and try to check it myself, even with a capacitor and a button (capacitor for debouncing, otherwise I would get multiple edges...)
    Helpful post? Buy me a coffee.
  • #72 21638698
    divadiow
    Level 38  
    p.kaczmarek2 wrote:
    I can try making PR and leave it for @divadiow to test

    can do. just need to know what a test actually is for this. I don't know much (anything?) about IRQs and edges
  • ADVERTISEMENT
  • #73 21638802
    p.kaczmarek2
    Moderator Smart Home
    I've started playing around interrupts.
    It seems that on BL602, we need to pass pin index to the interrupt to clear the flag - it can be done via user data.
    First step:
    https://github.com/openshwprojects/OpenBK7231T_App/pull/1768
    I assume that we would do a wrapper call via function pointer in HAL...

    Added after 3 [minutes]:

    Same for W600
    Screenshot of C code changes in drv_bl0937.c showing GPIO interrupt handling updates

    Added after 33 [seconds]:

    Those platforms seem easier - no flag clear needed:
    Screenshot of C code showing GPIO interrupt handler functions for multiple platforms

    Added after 1 [minutes]:

    It seems that only PLATFORM_LN882H is tricky

    Added after 39 [minutes]:

    Update: currently not sure about gpio_install_isr_service, need to read up on it, seems like it will be called globally once?

    Added after 1 [hours] 28 [minutes]:

    Not sure about Realtek - how to access last argument (NULL), user data?
    Code: C / C++
    Log in, to see the code

    hmm event is an enumeration:
    Code: C / C++
    Log in, to see the code


    Added after 46 [seconds]:

    ah last argument is ID:
    Code: C / C++
    Log in, to see the code

    so it shall be passed as first one to interrupt

    Added after 10 [hours] 28 [minutes]:

    Almost ready, I will ask for feedback tomorrow

    Added after 6 [hours] 43 [minutes]:

    I didn't split it into multiple files (I will move it to HAL pins?) but it should be ready for testing:
    https://github.com/openshwprojects/OpenBK7231T_App/pull/1768
    @insmod can you check? @divadiow do you have any devices with BL0937?
    The most uncertain part is passing GPIO index to interrupt in HAL so it can call external handler.
    Helpful post? Buy me a coffee.
  • #74 21639409
    divadiow
    Level 38  
    p.kaczmarek2 wrote:
    @divadiow do you have any devices with BL0937

    not all platforms but yes to at least LN882H, BK7231N, BK7231T, ESP8266, RTL8710B, BL602
  • #75 21639411
    p.kaczmarek2
    Moderator Smart Home
    So the most simple check would be to see if BL0937 works there on main release and then on my PR, each separately
    Helpful post? Buy me a coffee.
  • #76 21639787
    max4elektroda
    Level 24  
    I can confirm LN882H working:

    OpenLN882H web panel showing power data and device control options Web interface of OpenLN882H showing voltage, power, and network status.

    Added after 1 [hours]:

    A question regarding the "original" topic ;-)

    If we want to use a generic clock without a reliable source to constantly set the clock (like ntp) we suffer from the fact that "g_secondsElapsed" might be quite unreliable.
    Especially my W800 is a bad example: g_secondsElapsed will be off for ~ 5 seconds after only one minute! So after 12 hours our clock is about 1 hour off.

    We can easily fix that by using rtos tics to get a quite reliable uptime.

    My question: Shall I use this exact uptime (only) for the clock or should we "set" g_secondsElapsed to the correct value regularly?

    In the case of W800 to avoid permanent "jumps" in time we would need to do that quite often, every 5 seconds or so ...
  • #77 21639876
    p.kaczmarek2
    Moderator Smart Home
    You can't move g_secondsElapsed back at runtime, it could break drivers logic. The best you can do is try rewriting g_secondsElapsed core mechanism to be more accurate, maybe with rtos ticks.
    Helpful post? Buy me a coffee.
  • #78 21639884
    max4elektroda
    Level 24  
    The code is really simple (might need to check on recently added platforms):

    
    #if PLATFORM_W600 || PLATFORM_W800
    #define TimeOut_t xTimeOutType 
    #endif
    uint32_t getUptime(){
       TimeOut_t myTimeout;
       /*
       // we use vTaskSetTimeOutState to get the number of xTicks (we could get them with xTaskGetTickCount(), too)
       // but the number of overflows ("xNumOfOverflows") is private and hence not accessable else ...
       void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
       {
          configASSERT( pxTimeOut );
          pxTimeOut->xOverflowCount = xNumOfOverflows;
          pxTimeOut->xTimeOnEntering = xTickCount;
       }
       */
       vTaskSetTimeOutState( &myTimeout );
       // for most platforms, ticks are ms, but we can't be sure (e.g. its not on W600/W800) so we use factor portTICK_RATE_MS to make sure we get ms
       uint32_t my_secondsElapsed = (uint32_t)((((uint64_t) myTimeout.xOverflowCount << (sizeof(portTickType)*8) | myTimeout.xTimeOnEntering)*portTICK_RATE_MS ) / 1000 );
    // this would set g_secondsElapsed
    //   g_secondsElapsed=my_secondsElapsed;
       ADDLOG_DEBUG(LOG_FEATURE_RAW, "g_secondsElapsed=%i   / my_secondsElapsed=%i (differs: %i)\r\n", g_secondsElapsed, my_secondsElapsed, (g_secondsElapsed - my_secondsElapsed));
       return my_secondsElapsed;
    }


    Added after 2 [minutes]:

    I'll try using this instead of g_secondsElapsed++

    Added after 30 [minutes]:

    Using this for now - working on W800, will test with others soon ...

    diff --git a/src/user_main.c b/src/user_main.c
    index a0ea6322..dbee5483 100644
    --- a/src/user_main.c
    +++ b/src/user_main.c
    @@ -583,6 +583,11 @@ float g_wifi_temperature = 0;
     static byte g_secondsSpentInLowMemoryWarning = 0;
     void Main_OnEverySecond()
     {
    +#if PLATFORM_W600 || PLATFORM_W800
    +#define TimeOut_t xTimeOutType 
    +#endif
    +       TimeOut_t myTimeout;    // to get uptime from xTicks 
    +
            int newMQTTState;
            const char* safe;
            int i;
    @@ -754,8 +759,9 @@ void Main_OnEverySecond()
                            }
                    }
            }
    -
    -       g_secondsElapsed++;
    +//     g_secondsElapsed++;
    +       vTaskSetTimeOutState( &myTimeout );
    +       g_secondsElapsed = (int)((((uint64_t) myTimeout.xOverflowCount << (sizeof(portTickType)*8) | myTimeout.xTimeOnEntering)*portTICK_RATE_MS ) / 1000 );
            if (bSafeMode) {
                    safe = "[SAFE] ";
            }


    Added after 2 [minutes]:

    insmod wrote:
    For beken, did you try change edge directly in interrupt? E.g. gpio_int_enable to opposite edge.

    Not tested for Beken yet, but its working om BL602, thanks @insmod !
  • #79 21639910
    p.kaczmarek2
    Moderator Smart Home
    We will integrate this "on change" interrupt into HAL later, as soon as basics are tested
    Helpful post? Buy me a coffee.
  • #80 21639912
    max4elektroda
    Level 24  
    p.kaczmarek2 wrote:
    We will integrate this "on change" interrupt into HAL later, as soon as basics are tested

    That hal-approach will really make things much easier, thanks a lot!
  • #82 21639922
    p.kaczmarek2
    Moderator Smart Home
    The next step is "Counter" role from Tasmota. Should be very easy. Do anyone know how it works in TAS? Is it "on change", or "on rising", or "on falling"?
    I guess we need :
    - Counter_any
    - Counter_h
    - Counter_l ? or how should we name it?

    BTW: Little offtopic, but I also got ESP32-S3-ETH-8DI-8RO, I'm trying to put together a TCA9554 driver for it quickly
    https://github.com/openshwprojects/OpenBK7231T_App/pull/1770
    We need 8MB ESP partitions soon..
    Helpful post? Buy me a coffee.
  • ADVERTISEMENT
  • #83 21639923
    insmod
    Level 31  
    >>21639922
    Why? 4MB is enough for everything.
  • #84 21639966
    max4elektroda
    Level 24  
    p.kaczmarek2 wrote:
    The next step is "Counter" role from Tasmota. Should be very easy. Do anyone know how it works in TAS? Is it "on change", or "on rising", or "on falling"?
    I guess we need :
    - Counter_any
    - Counter_h
    - Counter_l ? or how should we name it?

    Don't know TAS behavior, so I'm no help here.

    What would you count? States? Then _h or _l are fine.
    If you count edges, I would propose _r(aising) and _f(alling)
  • #85 21639968
    p.kaczmarek2
    Moderator Smart Home
    Does 4MB/8MB partitions are taken into account as LFS limit or is limit outside the partitions? On OpenESP32.
    Helpful post? Buy me a coffee.
  • #86 21639974
    insmod
    Level 31  
    >>21639968
    Limit is partition size. So 8MB with 4MB firmware - LFS partition is the same as if it was on 4MB device.
    But isn't 320KB enough?
  • #87 21640066
    divadiow
    Level 38  
    >>21639409

    animated images

    BK7231N 1.18.156
    OpenBK7231N interface showing voltage, current, and energy metrics

    BK7231N 1768_merge_cf30e28012eb ✅
    OpenBK7231N interface showing power usage and status data

    BK7231N_ALT 1.18.156
    OpenBK7231N interface with OFF status and detailed power metrics

    BK7231N_ALT 1768_merge_cf30e28012eb ✅
    OpenBK7231N web interface showing energy data and OFF device status

    BK7231T 1.18.156
    OpenBK7231T interface showing status OFF and electrical energy metrics

    BK7231T 1768_merge_cf30e28012eb ✅
    OpenBK7231T interface showing power data and OFF status

    BK7231T_ALT 1.18.156
    OpenBK7231T interface showing voltage, current, and energy usage details

    BK7231T_ALT 1768_merge_cf30e28012eb ✅
    OpenBK7231T interface showing energy readings and OFF power state

    (new SDK still does its spikey/jumpy reading thing on any release)
  • #88 21640070
    insmod
    Level 31  
    >>21640066
    Set loglevel to 0 and spikes will 'magically' disappear.
  • #89 21640079
    divadiow
    Level 38  
    insmod wrote:
    Set loglevel to 0 and spikes will 'magically' disappear.

    ooh ok.

    damn. ESP8266 BL0937 device is 1mb.
  • #90 21640087
    p.kaczmarek2
    Moderator Smart Home
    I'm not sure about 8MB usage yet, so it's probably not a priority.

    Does HTTPS works on ESP build?

    I added counter_f:
    https://github.com/openshwprojects/OpenBK7231...mits/f99158f21f5ae95c2155209256e92ed3674d414d
    Still , one silly bug fix to come.

    I hope to be able to use counter_f along with button and capacitor (to debounce) to test interrupts
    Helpful post? Buy me a coffee.

Topic summary

✨ The discussion revolves around implementing a local clock in OpenBeken devices without relying on the NTP protocol. The initial approach involved using a variable to track the time since startup, allowing for time calculations based on elapsed seconds. While this method lacks the accuracy provided by NTP, it offers advantages such as independence from network connectivity and reduced resource requirements. Participants provided feedback on code structure, suggested improvements for compatibility, and discussed the potential for using real-time clocks (RTC) for enhanced accuracy. Testing across various platforms, including LN882H, BL602, and W600, was conducted to evaluate the clock's performance and reliability. The conversation also touched on daylight saving time adjustments and the possibility of remote clock synchronization.
Generated by the language model.

FAQ

TL;DR: A tuned ‘local clock’ for OpenBeken now drifts only 1–2 s per day—down from 120 s—after switching to RTOS-tick math; “good enough for daily energy stats” [Elektroda, max4elektroda, post #21031093] Why it matters: You can timestamp logs even when Wi-Fi or Internet is absent.

Quick Facts

• Typical drift after optimisation: 1–2 s / day ≈ 0.002 % [Elektroda, max4elektroda, post #21031093] • Tick counter overflow period: ~50 days with 32-bit FreeRTOS ticks [Elektroda, max4elektroda, post #21063405] • Code gated by #defines ENABLE_LOCAL_CLOCK & ENABLE_LOCAL_CLOCK_ADVANCED (default OFF) [Elektroda, max4elektroda, post #21032907] • Extra flash footprint: “only some bytes” when feature enabled [Elektroda, max4elektroda, post #21035091] • Tested platforms: BK7231T/N, LN882H, BL602, W600; BL602 showed watchdog resets edge-case [Elektroda, divadiow, post #21055037]

How does the new OpenBeken clock work without NTP?

At boot the firmware stores the startup Unix time in a variable and adds the ever-growing g_secondsElapsed value, now calculated from precise RTOS ticks. This produces current time even in AP-only mode, with no network traffic [Elektroda, max4elektroda, post #21031093]

What accuracy can I expect?

Field tests show 1–2 seconds drift per 24 hours across LN882H and BK7231 chips, versus the original 2-minute drift [Elektroda, divadiow, #21054381; Elektroda, max4elektroda, #21031093].

Which microcontrollers are supported?

Source builds succeed for BK7231T/N, LN882H, BL602 and W600 once the extra driver file drv_deviceclock.c is added to each platform’s Makefile or CMakeLists.txt [Elektroda, max4elektroda, post #21031093]

How do I enable the feature?

  1. Open obk_config.h.
  2. Set ENABLE_LOCAL_CLOCK 1 (and ENABLE_LOCAL_CLOCK_ADVANCED 1 for DST logic).
  3. Re-compile and flash. The GUI now shows “Offline Time System” with a ‘Set to browser time’ button [Elektroda, max4elektroda, post #21032907]

Can I still use NTP afterwards?

Yes. NTP can initialise the clock once; if the service stops, the local clock keeps running using the stored sync point plus ticks, avoiding freeze issues seen when only NTP_OnEverySecond() drove time [Elektroda, max4elektroda, post #21031093]

How is daylight-saving time handled?

The ADVANCED flag loads a DST table modelled on Tasmota. Future commits allow runtime configuration, not just compile-time tables, saving the rule set in a new uint64 config field [Elektroda, max4elektroda, post #21063405]

Will tick counter overflow break timekeeping?

No. The algorithm uses unsigned subtraction, so when the 32-bit tick counter wraps (~50 days) the math still yields correct deltas [Elektroda, max4elektroda, post #21063405]

How can I set the clock remotely?

Send HTTP GET /cm?cmnd=clock_set%201713880000 (example) from any LAN host; a router cron job can push time after reboot, avoiding WAN access [Elektroda, max4elektroda, post #21038303]

Can one OpenBeken act as NTP server for others?

Not yet. Current firmware lacks NTP-server code, but any device can HTTP-push its local time to peers. An internal NTP server is on the roadmap [Elektroda, omniron, post #21038282]

Does the new code bloat firmware size?

Link-time optimisation drops unused functions; only entry points inside #ifdef blocks compile. Developers report negligible flash increase—“only some bytes” [Elektroda, p.kaczmarek2, #21032115; Elektroda, max4elektroda, #21035091].

What happens after a power loss?

Because no RTC is present, the clock resets. Script another node to POST the correct time at boot, or add an external RTC like DS3231 for ±1 min/year accuracy [Elektroda, omniron, post #21034483]

Is the feature ready for production?

Maintainer feedback calls the pull request “very professional… hope we can merge it soon” [Elektroda, p.kaczmarek2, post #21053508] Until merged, you must build from the PR branch.
Generated by the language model.
ADVERTISEMENT