From c4f6f01f7e2b662bf5c2396d63bbdc7f44bdefeb Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Wed, 5 Mar 2025 14:20:40 +0100 Subject: [PATCH 1/3] fix #2446, pc0Flow for all boilers, fix #2411 --- src/devices/boiler.cpp | 32 +++++++++++++++++++++----------- src/devices/boiler.h | 2 +- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 0ae937379..0929c3f52 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -335,6 +335,11 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const MAKE_CF_CB(set_emergency_temp), 15, 70); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc0Flow_, DeviceValueType::INT16, FL_(pc0Flow), DeviceValueUOM::LH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc1Flow_, DeviceValueType::INT16, FL_(pc1Flow), DeviceValueUOM::LH); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc1On_, DeviceValueType::BOOL, FL_(pc1On), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc1Rate_, DeviceValueType::UINT8, FL_(pc1Rate), DeviceValueUOM::PERCENT); + /* * Hybrid heatpump with telegram 0xBB is readable and writeable in boiler and thermostat * thermostat always overwrites settings in boiler @@ -541,7 +546,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const register_device_value(DeviceValueTAG::TAG_DHW1, &nrgSuppWw_, DeviceValueType::UINT24, FL_(nrgSuppWw), DeviceValueUOM::KWH); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppCooling_, DeviceValueType::UINT24, FL_(nrgSuppCooling), DeviceValueUOM::KWH); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &nrgSuppPool_, DeviceValueType::UINT24, FL_(nrgSuppPool), DeviceValueUOM::KWH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPower_, DeviceValueType::UINT8, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPower), DeviceValueUOM::KW); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpPower_, DeviceValueType::UINT16, DeviceValueNumOp::DV_NUMOP_DIV10, FL_(hpPower), DeviceValueUOM::KW); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &hpMaxPower_, DeviceValueType::UINT8, @@ -684,7 +689,12 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const FL_(auxHeaterOff), DeviceValueUOM::NONE, MAKE_CF_CB(set_additionalHeater)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &auxHeaterStatus_, DeviceValueType::BOOL, FL_(auxHeaterStatus), DeviceValueUOM::NONE); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &auxHeaterStatus_, + DeviceValueType::ENUM, + FL_(enum_hpactivity), + FL_(auxHeaterStatus), + DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &auxHeaterLevel_, DeviceValueType::UINT8, FL_(auxHeaterLevel), DeviceValueUOM::PERCENT); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &auxHeaterDelay_, @@ -856,10 +866,6 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const FL_(hpPowerLimit), DeviceValueUOM::W, MAKE_CF_CB(set_hpPowerLimit)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc0Flow_, DeviceValueType::INT16, FL_(pc0Flow), DeviceValueUOM::LH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc1Flow_, DeviceValueType::INT16, FL_(pc1Flow), DeviceValueUOM::LH); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc1On_, DeviceValueType::BOOL, FL_(pc1On), DeviceValueUOM::NONE); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &pc1Rate_, DeviceValueType::UINT8, FL_(pc1Rate), DeviceValueUOM::PERCENT); // heatpump DHW settings register_device_value(DeviceValueTAG::TAG_DHW1, @@ -1660,13 +1666,17 @@ void Boiler::process_HpPower(std::shared_ptr telegram) { // has_bitupdate(telegram, heating_, 0, 0); // heating on? https://github.com/emsesp/EMS-ESP32/discussions/1898 has_bitupdate(telegram, hpSwitchValve_, 0, 4); + has_bitupdate(telegram, elHeatStep1_, 3, 0); + has_bitupdate(telegram, elHeatStep2_, 3, 1); + has_bitupdate(telegram, elHeatStep3_, 3, 2); has_bitupdate(telegram, hpCompOn_, 3, 4); has_bitupdate(telegram, hpEA0_, 3, 6); has_update(telegram, hpCircSpd_, 4); has_update(telegram, hpBrinePumpSpd_, 5); has_update(telegram, auxHeaterLevel_, 6); has_update(telegram, hpActivity_, 7); - has_update(telegram, hpPower_, 11); + has_update(telegram, auxHeaterStatus_, 8); + has_update(telegram, hpPower_, 10); has_update(telegram, hpCompSpd_, 17); has_bitupdate(telegram, hpInput[0].state, 1, 4); @@ -1967,7 +1977,7 @@ void Boiler::process_HpSilentMode(std::shared_ptr telegram) { // Boiler(0x08) -B-> All(0x00), ?(0x0488), data: 8E 00 00 00 00 00 01 03 void Boiler::process_HpValve(std::shared_ptr telegram) { - has_bitupdate(telegram, auxHeaterStatus_, 0, 2); + // has_bitupdate(telegram, auxHeaterStatus_, 0, 2); has_update(telegram, auxHeatMixValve_, 7); has_update(telegram, pc1Rate_, 13); // percent } @@ -2028,9 +2038,9 @@ void Boiler::process_HpSettings3(std::shared_ptr telegram) { has_update(telegram, primePump_, 4); has_update(telegram, primePumpMod_, 5); // has_update(telegram, hp3wayValve_, 6); // read in 48D - has_update(telegram, elHeatStep1_, 7); - has_update(telegram, elHeatStep2_, 8); - has_update(telegram, elHeatStep3_, 9); + // has_update(telegram, elHeatStep1_, 7); + // has_update(telegram, elHeatStep2_, 8); + // has_update(telegram, elHeatStep3_, 9); } // boiler(0x08) -W-> Me(0x0B), ?(0x04AE), data: 00 00 BD C4 00 00 5B 6A 00 00 00 24 00 00 62 59 00 00 00 00 00 00 00 00 diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 88b23f582..e8783aa0d 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -194,7 +194,7 @@ class Boiler : public EMSdevice { uint16_t maintenanceTime_; // heatpump - uint8_t hpPower_; + uint16_t hpPower_; uint8_t hpCompOn_; uint8_t hpBrinePumpSpd_; uint8_t hpCompSpd_; From 18bdcfe0505d5faaceea2b9e1fb3bac327e3c41f Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Mar 2025 18:12:05 +0100 Subject: [PATCH 2/3] fix lastcode #2438, heating/tapwater for heatpumps from activity #2450 --- src/devices/boiler.cpp | 23 ++++++++++++++--------- src/version.h | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 0929c3f52..5f528888e 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -1482,7 +1482,7 @@ void Boiler::process_UBAMonitorSlow(std::shared_ptr telegram) { */ void Boiler::process_UBAMonitorSlowPlus2(std::shared_ptr telegram) { has_update(telegram, absBurnPow_, 13); // current burner absolute power (percent of rating plate power) - if (model() == EMSdevice::EMS_DEVICE_FLAG_HIU || model() == EMSdevice::EMS_DEVICE_FLAG_HEATPUMP) { + if (model() == EMSdevice::EMS_DEVICE_FLAG_HIU) { uint8_t state = EMS_VALUE_UINT8_NOTSET; boilerState_ = 0; if (telegram->read_value(state, 2)) { @@ -1492,6 +1492,7 @@ void Boiler::process_UBAMonitorSlowPlus2(std::shared_ptr telegra if (telegram->read_value(state, 5)) { boilerState_ |= state == 1 ? 0x0A : 0; // dhw 0/1 } + check_active(); // do a quick check to see if the hot water or heating is active } } @@ -1688,6 +1689,8 @@ void Boiler::process_HpPower(std::shared_ptr telegram) { // has_update(hpCoolingOn_, hpActivity_ == 2 ? 0xFF : 0); // has_update(hpWwOn_, hpActivity_ == 3 ? 0xFF : 0); // has_update(hpPoolOn_, hpActivity_ == 4 ? 0xFF : 0); + boilerState_ = hpActivity_ == 1 ? 0x09 : hpActivity_ == 3 ? 0x0A : 0; + check_active(); // do a quick check to see if the hot water or heating is active } // Heatpump temperatures - type 0x48F @@ -1845,15 +1848,19 @@ void Boiler::process_UBAErrorMessage(std::shared_ptr telegram) { uint32_t date = (year - 2000) * 535680UL + month * 44640UL + day * 1440UL + hour * 60 + min + duration; // check valid https://github.com/emsesp/EMS-ESP32/issues/2189 if (day == 0 || day > 31 || month == 0 || month > 12 || !std::isprint(code[0]) || !std::isprint(code[1])) { + if (!lastCodeDate_) { + char newCode[sizeof(lastCode_)]; + snprintf(newCode, sizeof(lastCode_), "%s(%d)", code, codeNo); + has_update(lastCode_, newCode, sizeof(lastCode_)); + } return; } // store only the newest code from telegrams 10 and 11 - if (date > lastCodeDate_ && lastCodeDate_) { + if (date > lastCodeDate_) { lastCodeDate_ = date; - snprintf(lastCode_, sizeof(lastCode_), "%s(%d) %02d.%02d.%d %02d:%02d (%d min)", code, codeNo, day, month, year, hour, min, duration); - has_update(lastCode_); - } else if (!lastCodeDate_) { // no publish for first read - lastCodeDate_ = 1; + char newCode[sizeof(lastCode_)]; + snprintf(newCode, sizeof(lastCode_), "%s(%d) %02d.%02d.%d %02d:%02d (%d min)", code, codeNo, day, month, year, hour, min, duration); + has_update(lastCode_, newCode, sizeof(lastCode_)); } } @@ -1919,11 +1926,9 @@ void Boiler::process_UBAErrorMessage2(std::shared_ptr telegram) snprintf(&code[3], sizeof(code) - 3, "(%d) @uptime %lu - %lu min", codeNo, starttime, endtime); date = starttime; } - if (date > lastCodeDate_ && lastCodeDate_) { + if (date > lastCodeDate_) { lastCodeDate_ = date; has_update(lastCode_, code, sizeof(lastCode_)); - } else if (!lastCodeDate_) { - lastCodeDate_ = 1; } } diff --git a/src/version.h b/src/version.h index 7452a437a..c5e1f4c7a 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.2-dev.25" +#define EMSESP_APP_VERSION "3.7.2-dev.26" From 85c78bc8e9955b95672996f292db0c67c3c21668 Mon Sep 17 00:00:00 2001 From: MichaelDvP Date: Fri, 7 Mar 2025 18:23:40 +0100 Subject: [PATCH 3/3] update pkg --- interface/package.json | 12 +++--- interface/yarn.lock | 86 +++++++++++++++++++++--------------------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/interface/package.json b/interface/package.json index d4484a6af..4fdaa89c9 100644 --- a/interface/package.json +++ b/interface/package.json @@ -24,10 +24,10 @@ "@alova/adapter-xhr": "2.1.1", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", - "@mui/icons-material": "^6.4.6", - "@mui/material": "^6.4.6", + "@mui/icons-material": "^6.4.7", + "@mui/material": "^6.4.7", "@table-library/react-table-library": "4.1.12", - "alova": "3.2.9", + "alova": "3.2.10", "async-validator": "^4.2.5", "jwt-decode": "^4.0.0", "mime-types": "^2.1.35", @@ -35,7 +35,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "react-icons": "^5.5.0", - "react-router": "^7.2.0", + "react-router": "^7.3.0", "react-toastify": "^11.0.5", "typesafe-i18n": "^5.26.2", "typescript": "^5.8.2" @@ -52,13 +52,13 @@ "@types/react-dom": "^19.0.4", "concurrently": "^9.1.2", "eslint": "^9.21.0", - "eslint-config-prettier": "^10.0.2", + "eslint-config-prettier": "^10.1.1", "formidable": "^3.5.2", "prettier": "^3.5.3", "rollup-plugin-visualizer": "^5.14.0", "terser": "^5.39.0", "typescript-eslint": "8.26.0", - "vite": "^6.2.0", + "vite": "^6.2.1", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^5.1.4" }, diff --git a/interface/yarn.lock b/interface/yarn.lock index 8dc9a3278..4c45e2b42 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -783,36 +783,36 @@ __metadata: languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^6.4.6": - version: 6.4.6 - resolution: "@mui/core-downloads-tracker@npm:6.4.6" - checksum: 10c0/8b696639c7e803f264080b7b35fb266ffc9442877edd3a25ef48b0b78986f717720bd20e034877078f123a23d63bc2e1489693f0438722201d68db4bd0cf438a +"@mui/core-downloads-tracker@npm:^6.4.7": + version: 6.4.7 + resolution: "@mui/core-downloads-tracker@npm:6.4.7" + checksum: 10c0/c29ab1b11f772becf9231c8aa4c9f2b4b1749736c6d13179c83cc043ab9ddb863971d7d515b71160b35e19a9a61fe3ce2622c13bf95c1f62995114e20f86de7b languageName: node linkType: hard -"@mui/icons-material@npm:^6.4.6": - version: 6.4.6 - resolution: "@mui/icons-material@npm:6.4.6" +"@mui/icons-material@npm:^6.4.7": + version: 6.4.7 + resolution: "@mui/icons-material@npm:6.4.7" dependencies: "@babel/runtime": "npm:^7.26.0" peerDependencies: - "@mui/material": ^6.4.6 + "@mui/material": ^6.4.7 "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/a49cb504e12c10a852b4ebf67187b716ec41861d51d1dff3c7c0d6c3307b7ffca1f180fb512b1913361599655b6361c5ad1c2a98db61a2a45bedaa4ee6a1fb11 + checksum: 10c0/7e7b1b1ea904d67b333e259b335ff17186454cf89b0c0c95a507784a1fcd899899e956f8ceb9bbecbc0f6f8417fdc55de69f081a5d2bb8bffb982cd972efb77e languageName: node linkType: hard -"@mui/material@npm:^6.4.6": - version: 6.4.6 - resolution: "@mui/material@npm:6.4.6" +"@mui/material@npm:^6.4.7": + version: 6.4.7 + resolution: "@mui/material@npm:6.4.7" dependencies: "@babel/runtime": "npm:^7.26.0" - "@mui/core-downloads-tracker": "npm:^6.4.6" - "@mui/system": "npm:^6.4.6" + "@mui/core-downloads-tracker": "npm:^6.4.7" + "@mui/system": "npm:^6.4.7" "@mui/types": "npm:^7.2.21" "@mui/utils": "npm:^6.4.6" "@popperjs/core": "npm:^2.11.8" @@ -825,7 +825,7 @@ __metadata: peerDependencies: "@emotion/react": ^11.5.0 "@emotion/styled": ^11.3.0 - "@mui/material-pigment-css": ^6.4.6 + "@mui/material-pigment-css": ^6.4.7 "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -838,7 +838,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 10c0/62658532b2217a3ddbec8e90b302720a57a848bc2395f974d0119f65a31169499ba85a2d1a4037a843b4a1b50e8e5adc1705a47e82dac5e681cdd9e0a542571a + checksum: 10c0/0916ac0e0e5fb7de8cfe00d52f54e9f6a554ee1db7e228bcbaf3db437d6dbb259011a713017d27af09fe52fd1ca007a97ff0e2cceee227ec14aa2b219fc20a65 languageName: node linkType: hard @@ -882,9 +882,9 @@ __metadata: languageName: node linkType: hard -"@mui/system@npm:^6.4.6": - version: 6.4.6 - resolution: "@mui/system@npm:6.4.6" +"@mui/system@npm:^6.4.7": + version: 6.4.7 + resolution: "@mui/system@npm:6.4.7" dependencies: "@babel/runtime": "npm:^7.26.0" "@mui/private-theming": "npm:^6.4.6" @@ -906,7 +906,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: 10c0/014deda953d252b9244ac759b7644472c5eda2eb2bfd8460f9e1f727e375ec4043db7bbc6def11fcd5a7074966edd7f9453c2aef5a06251a40f8621b51289231 + checksum: 10c0/af36d946640222d7af8b04cfca3acade786c537c386d55c8519a21dbc8eff64f4e89c1096b9ccbd3944002fa0fb7ee5ccec87b1290953500d979a2605cf4e2ee languageName: node linkType: hard @@ -1597,8 +1597,8 @@ __metadata: "@emotion/react": "npm:^11.14.0" "@emotion/styled": "npm:^11.14.0" "@eslint/js": "npm:^9.21.0" - "@mui/icons-material": "npm:^6.4.6" - "@mui/material": "npm:^6.4.6" + "@mui/icons-material": "npm:^6.4.7" + "@mui/material": "npm:^6.4.7" "@preact/compat": "npm:^18.3.1" "@preact/preset-vite": "npm:^2.10.1" "@table-library/react-table-library": "npm:4.1.12" @@ -1607,11 +1607,11 @@ __metadata: "@types/node": "npm:^22.13.9" "@types/react": "npm:^19.0.10" "@types/react-dom": "npm:^19.0.4" - alova: "npm:3.2.9" + alova: "npm:3.2.10" async-validator: "npm:^4.2.5" concurrently: "npm:^9.1.2" eslint: "npm:^9.21.0" - eslint-config-prettier: "npm:^10.0.2" + eslint-config-prettier: "npm:^10.1.1" formidable: "npm:^3.5.2" jwt-decode: "npm:^4.0.0" mime-types: "npm:^2.1.35" @@ -1620,14 +1620,14 @@ __metadata: react: "npm:^19.0.0" react-dom: "npm:^19.0.0" react-icons: "npm:^5.5.0" - react-router: "npm:^7.2.0" + react-router: "npm:^7.3.0" react-toastify: "npm:^11.0.5" rollup-plugin-visualizer: "npm:^5.14.0" terser: "npm:^5.39.0" typesafe-i18n: "npm:^5.26.2" typescript: "npm:^5.8.2" typescript-eslint: "npm:8.26.0" - vite: "npm:^6.2.0" + vite: "npm:^6.2.1" vite-plugin-imagemin: "npm:^0.6.1" vite-tsconfig-paths: "npm:^5.1.4" languageName: unknown @@ -1677,13 +1677,13 @@ __metadata: languageName: node linkType: hard -"alova@npm:3.2.9": - version: 3.2.9 - resolution: "alova@npm:3.2.9" +"alova@npm:3.2.10": + version: 3.2.10 + resolution: "alova@npm:3.2.10" dependencies: "@alova/shared": "npm:1.1.2" rate-limiter-flexible: "npm:^5.0.3" - checksum: 10c0/f6f8393604791b9ece1cc656bfcebd3ba044ea81d2e9c871e2cfabaaea14e4720beb8f8eb354946cba040bb74dd73dbbcc70a5ede4fa31fcc6a236b79ececadb + checksum: 10c0/c559252ee8544c4cb286386b3d641bdb1105d69c183d214df99934a5c93185fc6da512198e9258bc6fcdd78af327a1100cb66f2bb1f1b617ee056b0aa57c5286 languageName: node linkType: hard @@ -3020,14 +3020,14 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:^10.0.2": - version: 10.0.2 - resolution: "eslint-config-prettier@npm:10.0.2" +"eslint-config-prettier@npm:^10.1.1": + version: 10.1.1 + resolution: "eslint-config-prettier@npm:10.1.1" peerDependencies: eslint: ">=7.0.0" bin: - eslint-config-prettier: build/bin/cli.js - checksum: 10c0/e0ef3c442661a26fc6e82acec5bb9a418c4a8f65ec8adf0983d3aaba7716d2ed448358b063cce6e3c272c847d14cb856ddf30031770c6571e2b2c3e2a439afd4 + eslint-config-prettier: bin/cli.js + checksum: 10c0/3dbfdf6495dd62e2e1644ea9e8e978100dabcd8740fd264df1222d130001a1e8de05d6ed6c67d3a60727386a07507f067d1ca79af6d546910414beab19e7966e languageName: node linkType: hard @@ -5612,9 +5612,9 @@ __metadata: languageName: node linkType: hard -"react-router@npm:^7.2.0": - version: 7.2.0 - resolution: "react-router@npm:7.2.0" +"react-router@npm:^7.3.0": + version: 7.3.0 + resolution: "react-router@npm:7.3.0" dependencies: "@types/cookie": "npm:^0.6.0" cookie: "npm:^1.0.1" @@ -5626,7 +5626,7 @@ __metadata: peerDependenciesMeta: react-dom: optional: true - checksum: 10c0/eb3fe57405a90d22f0a5455a3f73ec60fe2808a579d37bf130c192dfde18ebab06353e2cda2ed0f67701a6c43445eab1c1b6caa1347e5635dc65ff3028b7c2e2 + checksum: 10c0/2965a8a7598afaeb5c4d10c3364452df924bed9b03f6b18d7049e4b93054e2412749d0621b2ff4cdd7791af9fb843148aefbea3db2ffc9f43ef68f9df0c0241d languageName: node linkType: hard @@ -6867,9 +6867,9 @@ __metadata: languageName: node linkType: hard -"vite@npm:^6.2.0": - version: 6.2.0 - resolution: "vite@npm:6.2.0" +"vite@npm:^6.2.1": + version: 6.2.1 + resolution: "vite@npm:6.2.1" dependencies: esbuild: "npm:^0.25.0" fsevents: "npm:~2.3.3" @@ -6915,7 +6915,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/db62c93d4a823e805c6f8429de035528b3c35cc7f6de4948b41e0528f94ed2ac55047d90f8534f626ef3a04e682883b570fe5ec9ee92f51bf0c3c210dbec5ac1 + checksum: 10c0/2c024376a840eae2ce9cfba98d62e9f1eae93caa8304875854dbc0740414aedcfbe157c2244567bd456cdb60a300312af02ae9b5c63c147d35cf4da3a0591312 languageName: node linkType: hard