Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update rules library version #144

Merged
merged 7 commits into from
Jan 10, 2025
Merged

Conversation

CurlyMoo
Copy link

@CurlyMoo CurlyMoo commented Dec 6, 2024

This should fix issue Egyras#557 and Egyras#573

@IgorYbema
Copy link
Owner

@CurlyMoo can I ask you to add support for the relays on the large heishamon to be controlled using rules? a new PR for this or in this PR is ok

@IgorYbema IgorYbema changed the base branch from main to 3.9b January 9, 2025 15:59
@CurlyMoo
Copy link
Author

CurlyMoo commented Jan 9, 2025

Can you point me to the location in the main source where the relays are currently controlled?

@IgorYbema
Copy link
Owner

IgorYbema commented Jan 9, 2025

void mqttGPIOCallback(char* topic, char* value) {

Status van de relays wordt dus niet bijgehouden. Relay wordt gewoon gezet op basis van ontvangen MQTT bericht.
Zelfde mag ook gewoon met rules gedaan worden. Er hoeft geen status bewaard te worden. Enige wat je nodig hebt is de twee defines uit gpio.h. De rest kan je helemaal onafhankelijk bij de rules implementeren.

#define relayOnePin 21
#define relayTwoPin 47

Ik besef me nu dat er ook nog geen http call voor de relays gemaaakt is.

@CurlyMoo
Copy link
Author

Done

@IgorYbema
Copy link
Owner

Taking this to v3.9b to be tested this weekend

@IgorYbema IgorYbema merged commit 0b02f88 into IgorYbema:3.9b Jan 10, 2025
1 check passed
@stumbaumr
Copy link

stumbaumr commented Jan 11, 2025

My current rules are no longer working with the current build from https://github.com/IgorYbema/HeishaMon/actions/runs/12723065851
I always empty the rules field and then upload them fresh. But they are not saved anymore.
My current rules...

I am rolling back to https://github.com/IgorYbema/HeishaMon/actions/runs/11672004741

@IgorYbema
Copy link
Owner

IgorYbema commented Jan 11, 2025

Thanks, I'll test it too.

@IgorYbema
Copy link
Owner

@stumbaumr I just loaded this firmware and your rules and it worked fine (on a large heishamon EPS32). Can you tell me what you did different?

@stumbaumr
Copy link

stumbaumr commented Jan 11, 2025

I am using a ESP8266 - the small one...

Here are my settings:

grafik

@IgorYbema
Copy link
Owner

Ok i'll test that tomorrow. Thanks

@IgorYbema
Copy link
Owner

It is loading fine on that same build on a ESP8266 heishamon with same settings in my test setup. So don't know why it is failing for you. Can you paste the logs while loading the rules with this firmware if you want to?

@stumbaumr
Copy link

stumbaumr commented Jan 12, 2025

Here is the log:

Sun Jan 12 22:48:39 2025 (157512): Calculated Watt on S0 port 1: 1618
rule #1 was prepared in 5774 microseconds
rule #1 bytecode was created in 13478 microseconds
bytecode: 48/48, heap: 32/32, stack: 4/4 bytes, varstack: 64/64 bytes
timer #10 set to 40 seconds
rule #1 was executed in 3202 microseconds
bytecode: 48/48, heap: 32/32, stack: 4/12 bytes, varstack: 64/64 bytes
rule #2 was prepared in 227215 microseconds
rule #2 bytecode was created in 650317 microseconds
bytecode: 496/496, heap: 92/92, stack: 4/12 bytes, varstack: 184/184 bytes
Sun Jan 12 22:48:43 2025 (160929): #maxPumpDutyBeforeDHW
ERROR: cannot compare < with a left char value
rules memory used: 1152 / 16384
Sun Jan 12 22:48:43 2025 (160941): Failed to load new rules, reverting back to older rules!

Tested on this build:
https://github.com/IgorYbema/HeishaMon/actions/runs/12736286709
with these rules:

on System#Boot then
   #stateBeforeDHW = 1;
   #OpModeBeforeDHW = 0;
   #targetLowBeforeDHW = 31;
   #targetHighBeforeDHW = 40;
   #maxPumpDutyBeforeDHW = 110;
   #offAtNight = 1;
   @SetPump = 0;
   setTimer(10, 40);
end

on timer=10 then
   setTimer(10, 30);
   $hour = %hour;
   $minute = %minute;
   if $hour == 6 && $minute == 0 then
      if @Outside_Temp < 12 then
         #maxPumpDutyBeforeDHW = 160;
         @SetMaxPumpDuty = #maxPumpDutyBeforeDHW;
      end
      if @Operating_Mode_State == 0 && #offAtNight == 2 && @Heatpump_State == 0 then
         #offAtNight = 1;
         @SetHeatpump = 1;
      end
   end
   if $hour == 9 && $minute == 0 && @Operating_Mode_State == 1 && #offAtNight == 2 && @Heatpump_State == 0 && @Outside_Temp > 27 then
      #offAtNight = 1;
      @SetHeatpump = 1;
   end
   if (( %hour == 13 && %minute == 0 && @DHW_Temp < ( @DHW_Target_Temp + @DHW_Heat_Delta )) || @DHW_Temp < 20 ) && @Operating_Mode_State < 3 then
      #stateBeforeDHW = @Heatpump_State;
      #OpModeBeforeDHW = @Operating_Mode_State;
      @SetHeatpump = 1;
      @SetOperationMode = #OpModeBeforeDHW + 4;
   end
   if $hour == 18 && $minute == 0 && #offAtNight == 1 && @Heatpump_State == 1 then
      if @Operating_Mode_State == 0 && @Room_Thermostat_Temp > 22 && @Outside_Temp > 9 then
         #offAtNight = 2;
      end
      if @Operating_Mode_State == 1 then
         #offAtNight = 2;
         @SetHeatpump = 0;
      end
   end
   if $hour == 20 && $minute == 0 then
      #maxPumpDutyBeforeDHW = 110;
      @SetMaxPumpDuty = #maxPumpDutyBeforeDHW;
      if @Operating_Mode_State == 0 && #offAtNight == 2 && @Heatpump_State == 1 then   
         @SetHeatpump = 0;
      end
   end
end

on @DHW_Power_Consumption then
   if @Heatpump_State == 1 && @Operating_Mode_State >= 3 && @DHW_Power_Consumption == 0 && ( @DHW_Temp >= @DHW_Target_Temp || @Main_Outlet_Temp >= @Main_Target_Temp ) then
      @SetHeatpump = #stateBeforeDHW;
      @SetOperationMode = #OpModeBeforeDHW;
   end
end
on @ThreeWay_Valve_State then
   if @ThreeWay_Valve_State == 1 then
      #targetLowBeforeDHW = @Z1_Heat_Curve_Target_Low_Temp;
      #targetHighBeforeDHW = @Z1_Heat_Curve_Target_High_Temp;
      #maxPumpDutyBeforeDHW = @Max_Pump_Duty;
      @SetOperationMode = #OpModeBeforeDHW + 4;
      $minDHWTarget = 45;
      $minOutside = 10;
      $maxDHWTarget = 52;
      $maxOutside = 25;
      $newDHWTarget = round($minDHWTarget + ((@Outside_Temp - $minOutside ) * ($maxDHWTarget - $minDHWTarget) / ($maxOutside - $minOutside)));
      if @Outside_Temp <= $minOutside then
         $newDHWTarget = $minDHWTarget;
      end
      if @Outside_Temp >= $maxOutside then
         $newDHWTarget = $maxDHWTarget;
      end
      if @DHW_Target_Temp != $newDHWTarget then
         @SetDHWTemp = $newDHWTarget;
      end
      $targetAfterDHW = ( @DHW_Target_Temp + 5 );
      @SetCurves = concat('{zone1:{heat:{target:{high:', $targetAfterDHW ,',low:', $targetAfterDHW ,'}}}}');
      @SetMaxPumpDuty = 160;
      @SetPump = 1;	  
   else
      @SetHeatpump = #stateBeforeDHW;
      @SetOperationMode = #OpModeBeforeDHW;
      @SetPump = 1;
      setTimer(20, 240);
   end
end
on timer=20 then
   @SetZ1HeatRequestTemperature = 5;
   @SetCurves = concat('{zone1:{heat:{target:{high:', #targetHighBeforeDHW ,',low:', #targetLowBeforeDHW ,'}}}}');
   @SetMaxPumpDuty = #maxPumpDutyBeforeDHW;
   @SetPump = 0;
end

on @Main_Target_Temp then
   throttle();
end
on @Main_Outlet_Temp then
   throttle();
end
on @Main_Inlet_Temp then
   throttle();
end
on throttle then
   if @Heatpump_State == 1 then
      if @Operating_Mode_State % 2 == 0 || @ThreeWay_Valve_State == 1 then
         #roomDelta = 0;
         if @Outside_Temp < 7 && @Room_Thermostat_Temp > 22 then
            #roomDelta = -1;
         end
         #outletDeltaHeat = @Main_Outlet_Temp  - @Main_Target_Temp + @Z1_Heat_Request_Temp - #roomDelta;
         if #outletDeltaHeat < 0.3 then
            $newQuietMode = 0;
         end
         if #outletDeltaHeat >= 1.6 then
            $newQuietMode = 3;
         end
         #newHeatRequest = floor( #outletDeltaHeat ) - 1;
         if #newHeatRequest > 5 then
            #newHeatRequest = 5;
            if #offAtNight == 1 && @Outside_Temp > 9 then
               #offAtNight = 2;
            end
         end
         if #newHeatRequest <= 0 && ( @Main_Outlet_Temp  - @Main_Target_Temp ) < 2 then
            #newHeatRequest = #roomDelta;
         end
         if @Z1_Heat_Request_Temp != #newHeatRequest then
            @SetZ1HeatRequestTemperature = #newHeatRequest;
         end
      else
         $outletDeltaCool = @Main_Outlet_Temp - @Main_Target_Temp + @Z1_Cool_Request_Temp;
         if $outletDeltaCool > 0 then
            $newQuietMode = 0;
         end
         if $outletDeltaCool <= -1 then
            $newQuietMode = 3;
         end
         $newCoolRequest = floor( $outletDeltaCool ) + 1;
         if $newCoolRequest < -2 then
            $newCoolRequest = -2;
         end
         if $newCoolRequest > 3 then
            $newCoolRequest = 3;
         end
         if @Z1_Cool_Request_Temp != $newCoolRequest then
            @SetZ1CoolRequestTemperature = $newCoolRequest;
         end
      end
      if @Quiet_Mode_Level != $newQuietMode then
         @SetQuietMode = $newQuietMode;
      end
   end
end

The line giving the problem is this:
if @Outside_Temp < 12 then

@stumbaumr
Copy link

@CurlyMoo
Copy link
Author

@IgorYbema What's the onboot default value of @Outside_Temp? Could it be that that value triggers the push of a string value?
https://github.com/IgorYbema/HeishaMon/blob/3.9b/HeishaMon/rules.cpp#L442-L458

Maybe the check_is_number contains a bug?
https://github.com/IgorYbema/HeishaMon/blob/3.9b/HeishaMon/rules.cpp#L351-L376

IgorYbema added a commit that referenced this pull request Jan 14, 2025
commit 38c7996
Author: IgorYbema <[email protected]>
Date:   Tue Jan 14 08:03:44 2025 +0100

    Websocket data refresh (#151)

    Add realtime refresh of data in webgui using websocket

commit 7ca46cc
Author: IgorYbema <[email protected]>
Date:   Sun Jan 12 20:03:39 2025 +0100

    remove heatpump model decoding

commit 7cc4c44
Author: IgorYbema <[email protected]>
Date:   Sun Jan 12 14:32:18 2025 +0100

    Update MQTT-Topics.md

commit 99f9a89
Author: IgorYbema <[email protected]>
Date:   Sun Jan 12 14:28:13 2025 +0100

    Update MQTT-Topics.md

commit 2103c31
Author: IgorYbema <[email protected]>
Date:   Sun Jan 12 10:47:49 2025 +0100

    some fixes

commit d27a1b4
Author: IgorYbema <[email protected]>
Date:   Sun Jan 12 10:42:06 2025 +0100

    some more bivalent changes

commit 85e688e
Author: IgorYbema <[email protected]>
Date:   Sun Jan 12 10:32:17 2025 +0100

    remove gpio16 control

commit bb92e3b
Author: IgorYbema <[email protected]>
Date:   Sun Jan 12 10:18:22 2025 +0100

    gpio readme update

commit 0368f8d
Author: IgorYbema <[email protected]>
Date:   Sat Jan 11 20:22:37 2025 +0100

    fix for stats

commit 2eee519
Author: IgorYbema <[email protected]>
Date:   Sat Jan 11 16:45:37 2025 +0100

    now better esp32 wifi reconnect

commit ba544b3
Author: IgorYbema <[email protected]>
Date:   Sat Jan 11 16:45:24 2025 +0100

    add option to ESP32 html code def

commit 9f846df
Author: krzbor <[email protected]>
Date:   Sat Nov 30 20:35:00 2024 +0100

    Asynchronous 1-wire reading

    Currently, 1-wire is read synchronously, which means the program is paused for up to 750ms. During this pause, a yield is called, ensuring that WiFi works correctly. However, other issues may arise, such as UART read buffer overflow.
    I have modified the code so that everything operates asynchronously.
    The previous solution to this problem contained a bug:
      if ((DALLASASYNC) && ((unsigned long)(millis() - dallasTimer) > ((1000 * dallasTimerWait) - 1000)) ) {
        DS18B20.requestTemperatures(); // get temperatures for next run 1 second before getting the temperatures (async)
      }
    The author assumed the code would execute only once, while in reality, it was executed multiple times per second before the reading.

    Correction of the comment for DALLASASYNC

commit c6c4d06
Author: IgorYbema <[email protected]>
Date:   Sat Jan 11 10:00:22 2025 +0100

    update bivalent code

    update bivalent code

commit 4de83c9
Merge: fc3d1cb 3451384
Author: IgorYbema <[email protected]>
Date:   Fri Jan 10 21:25:37 2025 +0100

    Merge branch '3.9b' of https://github.com/IgorYbema/HeishaMon into 3.9b

commit fc3d1cb
Author: IgorYbema <[email protected]>
Date:   Fri Jan 10 21:25:15 2025 +0100

    small fix

commit 3451384
Author: IgorYbema <[email protected]>
Date:   Fri Jan 10 21:21:46 2025 +0100

    sync up (#148)

    * remove unused dependencies

    * remove unused dependencies

    * improve note

    * Delete platformio.ini

    * Update LIBSUSED.md

    * Update decode.h

    * Update HeatPumpType.md

    * Update OptionalPCB.md

    * Update OptionalPCB.md

    * add bivalent heating

    * add bivalent heating

    * add bivalent heating

    edit heat pump to match my id,
    add  mixing valve opening

    * Update decode.h

    * fix model count

    * added more switch options to bivalent settings because of homeassistant-aquara plugin

    * Add stale action to autoclose old issues and PR's

    * fix: removed deprecated payload_template from yaml

    Update heishamon.yaml to work with version 2025.2.0

    * style(integrations): Fix indentation and remove trailing spaces in HASS

    * When initializing the memory, the parameters for the memset() function were swapped and the memory was not initialized.

    (the compiler warnings had pointed this out)

    * Update README.md

    * Update HeatPumpType.md

    * add KIT-WC09L3E5 Update HeatPumpType.md

    |50 | E2 D5 0C 67 00 83 92 0C 27 98 | WH-ADC0509L3E5AN | WH-WDG05LE5 | KIT-WC09L3E5 | 5 | 1ph | HP - split L-series 3kW elec heating - AN |

    * add KIT-WC09L3E5 Update decode.h

    |50 | E2 D5 0C 67 00 83 92 0C 27 98 | WH-ADC0509L3E5AN | WH-WDG05LE5 | KIT-WC09L3E5 | 5 | 1ph | HP - split L-series 3kW elec heating - AN |

    refer to Egyras#614

    * changed string representation of number to the to 52 Update decode.h

    "52", //string representation of number of known models (last model number + 1)

    * change to right number 51 Update HeatPumpType.md

    string representation of number 51 instead of 50

    * added new model combination 52 Update HeatPumpType.md

    |52 | E2 D5 0C 67 00 83 92 0C 27 98 | WH-SDC0509L3E5 | WH-WDG05LE5 | KIT-WC09L3E5 | 5 | 1ph | HP - split L-series 3kW elec heating |

    * add correct byte value for Model combination 52 Update HeatPumpType.md

    E2 D5 0B 34 99 83 92 0C 27 98

    * add model combination 52 Update decode.h

    WH-SDC0509L3E5

    E2 D5 0B 34 99 83 92 0C 27 98

    ---------

    Co-authored-by: Egyras <[email protected]>
    Co-authored-by: mi-hol <[email protected]>
    Co-authored-by: HighlyCompressedAir <[email protected]>
    Co-authored-by: Gosun <[email protected]>
    Co-authored-by: geduxas <[email protected]>
    Co-authored-by: Krilo_89 <[email protected]>
    Co-authored-by: Alexander Gil <[email protected]>
    Co-authored-by: Reichelt <[email protected]>
    Co-authored-by: thecem <[email protected]>

commit aba49b6
Merge: e48a4fb 47b4855
Author: IgorYbema <[email protected]>
Date:   Fri Jan 10 21:19:42 2025 +0100

    Merge branch '3.9b' of https://github.com/IgorYbema/HeishaMon into 3.9b

commit 47b4855
Author: CurlyMoo <[email protected]>
Date:   Fri Jan 10 19:21:38 2025 +0100

    Add GPIO function in rules to control GPIO's (#146)

    * Update README.md

    * Update HeatPumpType.md

    * Add GPIO function to control GPIO's

    ---------

    Co-authored-by: IgorYbema <[email protected]>

commit 95a863f
Author: CurlyMoo <[email protected]>
Date:   Fri Jan 10 19:21:14 2025 +0100

    Allow returning TOP with string values (#145)

    * Update README.md

    * Update HeatPumpType.md

    * Allow returning TOP with string values

    * Update rules library version

    ---------

    Co-authored-by: IgorYbema <[email protected]>

commit 0b02f88
Author: CurlyMoo <[email protected]>
Date:   Fri Jan 10 19:20:54 2025 +0100

    Update rules library version (#144)

    * Update README.md

    * Update rules library version

    * Update github workflow

    * Fix for calling events with variable parameters

    * Restore defines

    * Restore defines 2

    * Warn when too many conditions are stacked

    ---------

    Co-authored-by: IgorYbema <[email protected]>

commit a342884
Author: geduxas <[email protected]>
Date:   Fri Jan 10 20:19:51 2025 +0200

    Add new topics (#141)

    * Add new topics

    * Update README.md

    * Mixed with zones

    ---------

    Co-authored-by: IgorYbema <[email protected]>

commit aaa59db
Author: CurlyMoo <[email protected]>
Date:   Fri Jan 10 19:18:05 2025 +0100

    Force rules on boot despite crash (#143)

    * Allow forcing rules on boot despite crash

    * Fix wrong condition

    * Replace arrow with dot

    * Update upload artifact version

    * Fix wrong condition

    * Fix string length

commit e48a4fb
Author: IgorYbema <[email protected]>
Date:   Thu Jan 9 20:39:36 2025 +0100

    maybe better ESP32 wifi reconnect

commit d05c827
Author: CurlyMoo <[email protected]>
Date:   Mon Dec 16 19:25:29 2024 +0100

    Fix TSTRING parsing in conditionals (#139)

commit bbb0a70
Author: Grégoire Seux <[email protected]>
Date:   Mon Dec 16 19:24:03 2024 +0100

    Expose board type via mqtt (#140)

    * Expose board type via mqtt

commit 4e441c4
Author: IgorYbema <[email protected]>
Date:   Mon Dec 9 19:37:38 2024 +0100

    remove S0 GPIO settings

commit c3b20c6
Author: IgorYbema <[email protected]>
Date:   Wed Nov 27 19:23:39 2024 +0100

    update github workflow

commit de55d9d
Author: IgorYbema <[email protected]>
Date:   Sun Nov 24 20:19:57 2024 +0100

    move all channel scan to esp32 def only

commit c74e08b
Author: IgorYbema <[email protected]>
Date:   Sun Nov 24 10:57:42 2024 +0100

    add wifi all scan esp32 and revert log changes

commit 771297c
Author: IgorYbema <[email protected]>
Date:   Fri Nov 1 17:54:37 2024 +0100

    switch workflow to v4 artifacts upload

commit 40f5f18
Author: IgorYbema <[email protected]>
Date:   Fri Nov 1 17:52:28 2024 +0100

    change xtop detect method
@stumbaumr
Copy link

stumbaumr commented Jan 14, 2025

Why do you not use strtod() instead of creating your own check_is_number? Is that not in stdlib.h?

@IgorYbema
Copy link
Owner

Hmm it doesn't fail when the outside_temp is default (-128) but it fails when it has a valid value.
That is why I could not reproduce the error as I tried it on my test setup which doesn't have active data. It does fail on my heishamon which is connected to the heatpump

@CurlyMoo
Copy link
Author

Why do you not use strtod() instead of creating your own check_is_number? Is that not in stdlib.h?

Maybe we can try that instead? Can you do that first in your local context?

@IgorYbema
Copy link
Owner

This is wrong. Should be < and not <= I believe
while(pos <= len) {

@CurlyMoo
Copy link
Author

I have a similar function inside the rules library to parse number from a stream of data. Quit possible i made a mistake in their.

Why do you not use strtod() instead of creating your own check_is_number?

It's also always a good idea to give this feedback when the PR is still open 😉

@IgorYbema
Copy link
Owner

Using chatgpt I changed the function to this and now it seems to work:

static int8_t check_is_number(const char *str) {
  uint16_t pos = 0, nrdot = 0;
  size_t len = strlen(str);

  if (len == 0) {
    return -1;  // Empty string is not a number.
  }

  // Check the first character (optional '-' or a digit).
  if (str[0] != '-' && !isdigit((unsigned char)str[0])) {
    return -1;
  }

  // Traverse the rest of the string.
  for (pos = 1; pos < len; pos++) {
    char current = str[pos];

    if (current == '.') {
      nrdot++;
      if (nrdot > 1) {
        return -1;  // More than one dot.
      }
    } else if (!isdigit((unsigned char)current)) {
      return -1;  // Non-digit, non-dot character.
    }
  }

  // Valid number if all checks pass.
  return 0;
}

@IgorYbema
Copy link
Owner

@stumbaumr you can test this build when the actions is finished building it: https://github.com/IgorYbema/HeishaMon/actions/runs/12772225974

I will test it myself also after dinner

@CurlyMoo
Copy link
Author

This was the suggestion i got:

The function provided attempts to check if a given string represents a number by iterating through each character and applying certain conditions. However, there are a few issues with the logic and implementation that need to be addressed to make it work correctly. Here’s a corrected version of the function with explanations:

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>

static int8_t check_is_number(char *str) {
    uint16_t i = 0, nrdot = 0, pos = 0, len = strlen(str);
    char current;

    // Check if the string is empty
    if (len == 0) {
        return -1;
    }

    current = str[0];

    // Check the first character
    if (isdigit(current) || current == '-') {
        /* 
         * The dot cannot be the first character 
         * and we cannot have more than 1 dot 
         */
        while (pos < len) {
            current = str[pos];

            if (!(isdigit(current) || (i == 0 && current == '-') || (i > 0 && nrdot == 0 && current == '.'))) {
                return -1; // Invalid character found
            }

            if (current == '.') {
                nrdot++;
            }

            pos++;
            i++;
        }

        return 0; // It is a valid number
    } else {
        return -1; // Doesn't start with a digit or '-'
    }
}

Changes Made:

Boundary Condition Check:

  • Added a check if (len == 0) at the beginning to handle empty strings. An empty string should not be considered a number.

Loop Condition:

  • Changed while (pos <= len) to while (pos < len). This ensures that the loop terminates before attempting to access str[len], which is out of bounds.

Character Fetching:

  • Moved current = str[pos] inside the while loop to correctly fetch the current character on each iteration.

Return Values:

Changed return 0; inside the loop to return 0; after the loop to signify that all characters were valid.

Logic Corrections:

Dot Counting:

  • Counting of dots (.) is correctly handled with nrdot to ensure there's no more than one dot and that it cannot be the first character.

First Character Handling:

  • The first character can be a digit (0-9) or a minus sign (-). This is checked explicitly.

Subsequent Characters:

  • For subsequent characters, digits (0-9), a minus sign (only if it's the first character), and a dot (only if it hasn't been encountered before) are allowed.

Additional Considerations:

  • This function assumes ASCII characters and does not handle floating-point exponent notation (e or E). If you need to support scientific notation, additional logic would be necessary.
  • Make sure to include necessary header files (<stdio.h>, <stdint.h>, <string.h>, <ctype.h>) for the function to compile and work correctly in a C environment.

By applying these corrections, the function should now correctly determine whether the input string represents a valid number based on the specified criteria.

@stumbaumr
Copy link

stumbaumr commented Jan 14, 2025

Excellent work, ChatGPT!
It is working for me now and reading that code part became easier as well!
Running on https://github.com/IgorYbema/HeishaMon/actions/runs/12775259241 now...

Wow, that Websocket flickering on the "Current heatpump values" screen looks good...

Would be cool to have that automatic window scaling on the "Rules" screen like as we have it on the "Console" screen...

@CurlyMoo
Copy link
Author

@IgorYbema I also asked ChatGPT if we could replace my function with a standard C library function, and this was the answer:

#include <stdlib.h>  // for strtod
#include <ctype.h>   // for isdigit, though it's not needed in this version

static int8_t check_is_number(char *str) {
    char *endptr;
    
    // strtod() will convert the string and update endptr to point to the first invalid character
    strtod(str, &endptr);

    // If endptr points to the same location as the start of the string, the conversion failed
    // Also, the string must not be empty or contain only invalid characters
    if (*endptr != '\0') {
        return -1;
    }

    // Successful conversion means a valid number, otherwise return -1
    return 0;
}

@CurlyMoo
Copy link
Author

CurlyMoo commented Jan 14, 2025

Before someone complains why there is a need for this function:
https://github.com/IgorYbema/HeishaMon/blob/3.9b/HeishaMon/src/rules/rules.cpp#L298-L326

That's because this functions needs to be able to handle byte-by-byte memory reading as required by the 2nd heap. stdtod doesn't do that safe reading internally.

@stumbaumr
Copy link

There is still a bug with rules:
Simplified rule:

on System#Boot then
   #stateBeforeDHW = 1;
   #OpModeBeforeDHW = 0;
   #targetLowBeforeDHW = 31;
   #targetHighBeforeDHW = 40;
   #PumpDutyBeforeDHW = 110;
   #offAtNight = 1;
   @SetPump = 0;
   setTimer(10, 40);
end

on timer=10 then
   setTimer(10, 10);
   $hour = %hour;
   $minute = %minute;
   if $hour == 6 && $minute == 0 then
      if @Outside_Temp < 12 then
         #PumpDutyBeforeDHW = 160;
         @SetMaxPumpDuty = #PumpDutyBeforeDHW;
      end
      if @Operating_Mode_State == 0 && #offAtNight == 2 && @Heatpump_State == 0 then
         #offAtNight = 1;
         @SetHeatpump = 1;
      end
   end
   if $hour == 9 && $minute == 0 && @Operating_Mode_State == 1 && #offAtNight == 2 && @Heatpump_State == 0 && @Outside_Temp > 27 then
      #offAtNight = 1;
      @SetHeatpump = 1;
   end
   if (( %hour == 14 && %minute == 0 && @DHW_Temp < ( @DHW_Target_Temp + @DHW_Heat_Delta )) || @DHW_Temp < 20 ) && @Operating_Mode_State < 3 then
      #stateBeforeDHW = @Heatpump_State;
      #OpModeBeforeDHW = @Operating_Mode_State;
      @SetHeatpump = 1;
      @SetOperationMode = #OpModeBeforeDHW + 4;
   end
   if $hour == 18 && $minute == 0 && #offAtNight == 1 && @Heatpump_State == 1 then
      if @Operating_Mode_State == 0 && @Room_Thermostat_Temp > 22 && @Outside_Temp > 9 then
         #offAtNight = 2;
      end
      if @Operating_Mode_State == 1 then
         #offAtNight = 2;
         @SetHeatpump = 0;
      end
   end
   if $hour == 20 && $minute == 0 then
      #PumpDutyBeforeDHW = 110;
      @SetMaxPumpDuty = #PumpDutyBeforeDHW;
      if @Operating_Mode_State == 0 && #offAtNight == 2 && @Heatpump_State == 1 then   
         @SetHeatpump = 0;
      end
   end
end

Straight after saving switching to the console:

Wed Jan 15 12:19:42 2025 (54992464): Pulses seen on S0 port 1: Good: 43894 Bad: 9 Average good pulse width: 86
Wed Jan 15 12:19:42 2025 (54992468): Measured Watthour on S0 port 1: 1.50
Wed Jan 15 12:19:42 2025 (54992476): Measured total Watthour on S0 port 1: 4166662.50
Wed Jan 15 12:19:42 2025 (54992482): Calculated Watt on S0 port 1: 1042
Wed Jan 15 12:19:44 2025 (54993892): Heishamon stats: Uptime: 0 days 15 hours 16 minutes 33 seconds ## Free memory: 60% ## Heap fragmentation: 6% ## Max free block: 22680 bytes ## Free heap: 23976 bytes ## Wifi: 38% (RSSI: -81) ## Mqtt reconnects: 4 ## Correct data: 99.97% Rules active: 2
--- Unnecessary output removed ---
Wed Jan 15 12:20:14 2025 (55023898): Heishamon stats: Uptime: 0 days 15 hours 17 minutes 3 seconds ## Free memory: 73% ## Heap fragmentation: 5% ## Max free block: 27864 bytes ## Free heap: 29320 bytes ## Wifi: 38% (RSSI: -81) ## Mqtt reconnects: 4 ## Correct data: 99.97% Rules active: 2
Wed Jan 15 12:20:14 2025 (55023902): Requesting new panasonic data
Wed Jan 15 12:20:14 2025 (55023910): sent bytes: 111 including checksum value: 18 
Wed Jan 15 12:20:14 2025 (55024356): Received 203 bytes data
Wed Jan 15 12:20:14 2025 (55024358): Checksum and header received ok!
Wed Jan 15 12:20:14 2025 (55024362): received TOP62 Fan1_Motor_Speed: 580
Wed Jan 15 12:20:17 2025 (55027471): Pulses seen on S0 port 1: Good: 43915 Bad: 9 Average good pulse width: 86
Wed Jan 15 12:20:17 2025 (55027476): Measured Watthour on S0 port 1: 1.50
Wed Jan 15 12:20:17 2025 (55027483): Measured total Watthour on S0 port 1: 4166673.00
Wed Jan 15 12:20:17 2025 (55027490): Calculated Watt on S0 port 1: 1043
==== timer=10 ====
Wed Jan 15 12:20:18 2025 (55027815): #PumpDutyBeforeDHW
rule #2 was executed in 12627 microseconds

>>> local variables


>>> global variables

 0 #stateBeforeDHW = 1
 1 #OpModeBeforeDHW = 12
 2 #targetLowBeforeDHW = 20
 3 #targetHighBeforeDHW = 40
 4 #PumpDutyBeforeDHW = 110
 5 #offAtNight = 1
Wed Jan 15 12:20:19 2025 (55028899): Heishamon stats: Uptime: 0 days 15 hours 17 minutes 8 seconds ## Free memory: 73% ## Heap fragmentation: 5% ## Max free block: 27864 bytes ## Free heap: 29328 bytes ## Wifi: 40% (RSSI: -80) ## Mqtt reconnects: 4 ## Correct data: 99.97% Rules active: 2

The global variables have been modified where they should not have been (#OpModeBeforeDHW = 12 and #targetLowBeforeDHW = 20)
Very strange...
...need to make DHW so switching back to https://github.com/IgorYbema/HeishaMon/actions/runs/12714977590

@IgorYbema
Copy link
Owner

Yes I confirm this 2nd bug. I try to look which can cause this. #targetLowBeforeDHW is never changed in the timer routine but get changed anyway.

@IgorYbema
Copy link
Owner

Before someone complains why there is a need for this function: https://github.com/IgorYbema/HeishaMon/blob/3.9b/HeishaMon/src/rules/rules.cpp#L298-L326

Isn't that function wrong also as it also does pos <= len . Did you check?

@CurlyMoo
Copy link
Author

Isn't that function wrong also as it also does pos <= len . Did you check?

CurlyMoo/rules@6cd2237

@IgorYbema
Copy link
Owner

Yes I confirm this 2nd bug. I try to look which can cause this. #targetLowBeforeDHW is never changed in the timer routine but get changed anyway.

Ok I just confirmed that when reverting this PR that this issue gone. I'll try to revert the commits one by one of the PR to see where it went wrong

IgorYbema added a commit that referenced this pull request Jan 15, 2025
@IgorYbema
Copy link
Owner

Yes I confirm this 2nd bug. I try to look which can cause this. #targetLowBeforeDHW is never changed in the timer routine but get changed anyway.

I just reverted this commit for this PR and opened a new PR so we can handle the rules library update from there properly

#153

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants