diff --git a/.github/workflows/wled-ci.yml b/.github/workflows/wled-ci.yml index c906dc58a..26d14d0fa 100644 --- a/.github/workflows/wled-ci.yml +++ b/.github/workflows/wled-ci.yml @@ -1,4 +1,4 @@ -name: PlatformIO CI +name: WLED CI on: [push, pull_request] @@ -78,3 +78,17 @@ jobs: files: | *.bin *.bin.gz + + + testCdata: + name: Test cdata.js + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '20.x' + cache: 'npm' + - run: npm ci + - run: npm test diff --git a/CHANGELOG.md b/CHANGELOG.md index 17c37c530..2d3a683b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,27 @@ ## WLED changelog -#### Build 2309120 till build 2201060 +#### Build 2309120 till build 2401270 - WLED version 0.15.0-a0 +- BREAKING: Effect: updated Palette effect to support 2D (#3683 by @TripleWhy) +- "SuperSync" from WLED MM (by @MoonModules) +- Effect: DNA Spiral Effect Speed Fix (#3723 by @Derek4aty1) +- Fix for #3693 +- Orange flash fix (#3196) for transitions +- Add own background image upload (#3596 by @WoodyLetsCode) +- WLED time overrides (`WLED_NTP_ENABLED`, `WLED_TIMEZONE`, `WLED_UTC_OFFSET`, `WLED_LAT` and `WLED_LON`) +- Better sorting and naming of static palettes (by @WoodyLetsCode) +- ANIMartRIX usermod and effects (#3673 by @netmindz) +- Use canvas instead of CSS gradient for liveview (#3621 by @zanhecht) +- Fix for #3672 +- ColoOrderMap W channel swap (color order overrides now have W swap) +- En-/disable LED maps when receiving realtime data (#3554 by @ezcGman) +- Added PWM frequency selection to UI (Settings) +- Automatically build UI before compiling (#3598, #3666 by @WoodyLetsCode) +- Internal: Added *suspend* API to `strip` (`WS2812FX class`) +- Possible fix for #3589 & partial fix for #3605 +- MPU6050 upgrade (#3654 by @willmmiles) +- UI internals (#3656 by @WoodyLetsCode) +- ColorPicker fix (#3658 by @WoodyLetsCode) - Global JSON buffer guarding (#3648 by @willmmiles, resolves #3641, #3312, #3367, #3637, #3646, #3447) - Effect: Fireworks 1D (fix for matrix trailing strip) - BREAKING: Reduced number of segments (12) on ESP8266 due to less available RAM diff --git a/package-lock.json b/package-lock.json index 55fc0b17b..09d03e9fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,277 +1,434 @@ { "name": "wled", "version": "0.15.0-a0", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "abbrev": { + "packages": { + "": { + "name": "wled", + "version": "0.15.0-a0", + "license": "ISC", + "dependencies": { + "clean-css": "^5.3.3", + "html-minifier-terser": "^7.2.0", + "inliner": "^1.13.1", + "nodemon": "^3.0.2", + "zlib": "^1.0.5" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", + "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, - "ajv": { + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { + "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "align-text": { + "node_modules/align-text": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "requires": { + "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", + "dependencies": { "kind-of": "^3.0.2", "longest": "^1.0.1", "repeat-string": "^1.5.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "ansi-escapes": { + "node_modules/ansi-escapes": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + "integrity": "sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw==", + "engines": { + "node": ">=0.10.0" + } }, - "ansi-regex": { + "node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } }, - "ansi-styles": { + "node_modules/ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "engines": { + "node": ">=0.10.0" + } }, - "anymatch": { + "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "requires": { + "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "argparse": { + "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { + "dependencies": { "sprintf-js": "~1.0.2" } }, - "asap": { + "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { "safer-buffer": "~2.1.0" } }, - "assert-plus": { + "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } }, - "asynckit": { + "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "aws-sign2": { + "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } }, - "aws4": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", - "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "bcrypt-pbkdf": { + "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { "tweetnacl": "^0.14.3" } }, - "binary-extensions": { + "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } }, - "boolbase": { + "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, - "brace-expansion": { + "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "braces": { + "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { + "dependencies": { "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "camelcase": { + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" + "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", + "engines": { + "node": ">=0.10.0" } }, - "chalk": { + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", + "dependencies": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "charset": { + "node_modules/charset": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", - "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==" + "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", + "engines": { + "node": ">=4.0.0" + } }, - "cheerio": { + "node_modules/cheerio": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz", - "integrity": "sha1-dy5wFfLuKZZQltcepBdbdas1SSU=", - "requires": { + "integrity": "sha512-Fwcm3zkR37STnPC8FepSHeSYJM5Rd596TZOcfDUdojR4Q735aK1Xn+M+ISagNneuCwMjK28w4kX+ETILGNT/UQ==", + "dependencies": { "css-select": "~1.0.0", "dom-serializer": "~0.1.0", "entities": "~1.1.1", "htmlparser2": "~3.8.1", "lodash": "^3.2.0" + }, + "engines": { + "node": ">= 0.6" } }, - "chokidar": { + "node_modules/cheerio/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "requires": { + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.3.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "clap": { + "node_modules/clap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", - "requires": { + "dependencies": { "chalk": "^1.1.3" + }, + "engines": { + "node": ">=0.10.0" } }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", - "requires": { + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dependencies": { "source-map": "~0.6.0" }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } + "engines": { + "node": ">= 10.0" } }, - "cliui": { + "node_modules/cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "requires": { + "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", + "dependencies": { "center-align": "^0.1.1", "right-align": "^0.1.1", "wordwrap": "0.0.2" } }, - "coa": { + "node_modules/coa": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", - "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", - "requires": { + "integrity": "sha512-KAGck/eNAmCL0dcT3BiuYwLbExK6lduR8DxM3C1TyDzaXhZHyZ8ooX5I5+na2e3dPFuibfxrGdorr0/Lr7RYCQ==", + "dependencies": { "q": "^1.1.2" + }, + "engines": { + "node": ">= 0.8.0" } }, - "colors": { + "node_modules/colors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" + "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", + "engines": { + "node": ">=0.1.90" + } }, - "combined-stream": { + "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { + "dependencies": { "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "configstore": { + "node_modules/configstore": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/configstore/-/configstore-1.4.0.tgz", - "integrity": "sha1-w1eB0FAdJowlxUuLF/YkDopPsCE=", - "requires": { + "integrity": "sha512-Zcx2SVdZC06IuRHd2MhkVYFNJBkZBj166LGdsJXRcqNC8Gs5Bwh8mosStNeCBBmtIm4wNii2uarD50qztjKOjw==", + "dependencies": { "graceful-fs": "^4.1.2", "mkdirp": "^0.5.0", "object-assign": "^4.0.1", @@ -281,285 +438,338 @@ "write-file-atomic": "^1.1.2", "xdg-basedir": "^2.0.0" }, - "dependencies": { - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" - } + "engines": { + "node": ">=0.10.0" } }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "node_modules/configstore/node_modules/uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha512-FULf7fayPdpASncVy4DLh3xydlXEJJpvIELjYjNeQWYUZ9pclcpvCZSr2gkmN2FrrGcI7G/cJsIEwk5/8vfXpg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details." }, - "css-select": { + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/css-select": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz", - "integrity": "sha1-sRIcpRhI3SZOIkTQWM7iVN7rRLA=", - "requires": { + "integrity": "sha512-/xPlD7betkfd7ChGkLGGWx5HWyiHDOSn7aACLzdH0nwucPvB0EAm8hMBm7Xn7vGfAeRRN7KZ8wumGm8NoNcMRw==", + "dependencies": { "boolbase": "~1.0.0", "css-what": "1.0", "domutils": "1.4", "nth-check": "~1.0.0" } }, - "css-what": { + "node_modules/css-what": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz", - "integrity": "sha1-18wt9FGAZm+Z0rFEYmOUaeAPc2w=" + "integrity": "sha512-60SUMPBreXrLXgvpM8kYpO0AOyMRhdRlXFX5BMQbZq1SIJCyNE56nqFQhmvREQdUJpedbGRYZ5wOyq3/F6q5Zw==", + "engines": { + "node": "*" + } }, - "csso": { + "node_modules/csso": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/csso/-/csso-2.0.0.tgz", - "integrity": "sha1-F4tDpEYhIhwndWCG9THgL0KQDug=", - "requires": { + "integrity": "sha512-tckZA0LhyEnToPoQDmncCA+TUS3aoIVl/MsSaoipR52Sfa+H83fJvIHRVOHMFn9zW6kIV1L0D7tUDFFjvN28lg==", + "dependencies": { "clap": "^1.0.9", "source-map": "^0.5.3" + }, + "bin": { + "csso": "bin/csso" + }, + "engines": { + "node": ">=0.10.0" } }, - "dashdash": { + "node_modules/csso/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" } }, - "debug": { + "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { + "dependencies": { "ms": "2.0.0" } }, - "decamelize": { + "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } }, - "deep-extend": { + "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } }, - "delayed-stream": { + "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } }, - "dom-serializer": { + "node_modules/dom-serializer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "requires": { + "dependencies": { "domelementtype": "^1.3.0", "entities": "^1.1.1" } }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz", - "integrity": "sha1-CGVRN5bGswYDGFDhdVFrr4C3Km8=", - "requires": { - "domelementtype": "1" - } - }, - "dot-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz", - "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==", - "requires": { - "no-case": "^3.0.3", - "tslib": "^1.10.0" - }, - "dependencies": { - "lower-case": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", - "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", - "requires": { - "tslib": "^1.10.0" - } - }, - "no-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", - "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", - "requires": { - "lower-case": "^2.0.1", - "tslib": "^1.10.0" - } - } - } - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "entities": { + "node_modules/dom-serializer/node_modules/entities": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" }, - "es6-promise": { + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "node_modules/domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/domutils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz", + "integrity": "sha512-ZkVgS/PpxjyJMb+S2iVHHEZjVnOUtjGp0/zstqKGTE9lrZtNHlNQmLwP/lhLMEApYbzc08BKMx9IFpKhaSbW1w==", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/duplexify/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/duplexify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es6-promise": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz", - "integrity": "sha1-lu258v2wGZWCKyY92KratnSBgbw=" + "integrity": "sha512-oyOjMhyKMLEjOOtvkwg0G4pAzLQ9WdbbeX7WdqKzvYXu+UFgD0Zo/Brq5Q49zNmnGPPzV5rmYvrr0jz1zWx8Iw==" }, - "escape-string-regexp": { + "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } }, - "esprima": { + "node_modules/esprima": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } }, - "extend": { + "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, - "extsprintf": { + "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] }, - "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "fast-json-stable-stringify": { + "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, - "fill-range": { + "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { + "dependencies": { "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "forever-agent": { + "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } }, - "form-data": { + "node_modules/form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { + "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" } }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "getpass": { + "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { "assert-plus": "^1.0.0" } }, - "glob-parent": { + "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { + "dependencies": { "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "got": { + "node_modules/got": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", - "integrity": "sha1-5dDtSvVfw+701WAHdp2YGSvLLso=", - "requires": { + "integrity": "sha512-7chPlc0pWHjvq7B6dEEXz4GphoDupOvBSSl6AwRsAJX7GPTZ+bturaZiIigX4Dp6KrAP67nvzuKkNc0SLA0DKg==", + "dependencies": { "duplexify": "^3.2.0", "infinity-agent": "^2.0.0", "is-redirect": "^1.0.0", @@ -571,166 +781,167 @@ "read-all-stream": "^3.0.0", "timed-out": "^2.0.0" }, - "dependencies": { - "object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" - } + "engines": { + "node": ">=0.10.0" } }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + "node_modules/got/node_modules/object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", + "engines": { + "node": ">=0.10.0" + } }, - "har-schema": { + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" } }, - "has-ansi": { + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dependencies": { "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "has-flag": { + "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "html-minifier-terser": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", - "requires": { - "camel-case": "^4.1.1", - "clean-css": "^4.2.3", - "commander": "^4.1.1", - "he": "^1.2.0", - "param-case": "^3.0.3", - "relateurl": "^0.2.7", - "terser": "^4.6.3" - }, - "dependencies": { - "camel-case": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", - "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", - "requires": { - "pascal-case": "^3.1.1", - "tslib": "^1.10.0" - } - }, - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" - }, - "param-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz", - "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==", - "requires": { - "dot-case": "^3.0.3", - "tslib": "^1.10.0" - } - } + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" } }, - "htmlparser2": { + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/htmlparser2": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", - "requires": { + "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", + "dependencies": { "domelementtype": "1", "domhandler": "2.3", "domutils": "1.5", "entities": "1.0", "readable-stream": "1.1" - }, - "dependencies": { - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" - } } }, - "http-signature": { + "node_modules/htmlparser2/node_modules/domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==" + }, + "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" } }, - "iconv-lite": { + "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { + "dependencies": { "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" } }, - "ignore-by-default": { + "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" }, - "imurmurhash": { + "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } }, - "infinity-agent": { + "node_modules/infinity-agent": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz", - "integrity": "sha1-ReDi/3qesDCyfWK3SzdEt6esQhY=" + "integrity": "sha512-CnfUJe5o2S9aAQWXGMhDZI4UL39MAJV3guOTfHHIdos4tuVHkl1j/J+1XLQn+CLIvqcpgQR/p+xXYXzcrhCe5w==" }, - "inherits": { + "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ini": { + "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, - "inliner": { + "node_modules/inliner": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/inliner/-/inliner-1.13.1.tgz", - "integrity": "sha1-5QApgev1Dp2fMTcRSBz/Ei1PP8s=", - "requires": { + "integrity": "sha512-yoS+56puOu+Ug8FBRtxtTFnEn2NHqFs8BNQgSOvzh3J0ommbwNw8VKiaVNYjWK6fgPuByq95KyV0LC+qV9IwLw==", + "dependencies": { "ansi-escapes": "^1.4.0", "ansi-styles": "^2.2.1", "chalk": "^1.1.3", @@ -750,619 +961,806 @@ "then-fs": "^2.0.0", "uglify-js": "^2.8.0", "update-notifier": "^0.5.0" + }, + "bin": { + "inliner": "cli/index.js" } }, - "is-binary-path": { + "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { + "dependencies": { "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "is-buffer": { + "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, - "is-extglob": { + "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } }, - "is-finite": { + "node_modules/is-finite": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "is-glob": { + "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { + "dependencies": { "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-npm": { + "node_modules/is-npm": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "js-yaml": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", - "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=", - "requires": { - "argparse": "^1.0.7", - "esprima": "^2.6.0" + "integrity": "sha512-9r39FIr3d+KD9SbX0sfMsHzb5PP3uimOiwr3YupUaUFG4W0l1U57Rx3utpttV7qz5U3jmrO5auUa04LU9pyHsg==", + "engines": { + "node": ">=0.10.0" } }, - "jsbn": { + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/js-yaml": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", + "integrity": "sha512-BLv3oxhfET+w5fjPwq3PsAsxzi9i3qzU//HMpWVz0A6KplF86HdR9x2TGnv9DXhSUrO7LO8czUiTd3yb3mLSvg==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^2.6.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" }, - "jschardet": { + "node_modules/jschardet": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.6.0.tgz", - "integrity": "sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ==" + "integrity": "sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ==", + "engines": { + "node": ">=0.1.90" + } }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, - "json-stringify-safe": { + "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" } }, - "kind-of": { + "node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dependencies": { "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "latest-version": { + "node_modules/latest-version": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-1.0.1.tgz", - "integrity": "sha1-cs/Ebj6NG+ZR4eu1Tqn26pbzdLs=", - "requires": { + "integrity": "sha512-HERbxp4SBlmI380+eM0B0u4nxjfTaPeydIMzl9+9UQ4nSu3xMWKlX9WoT34e4wy7VWe67c53Nv9qPVjS8fHKgg==", + "dependencies": { "package-json": "^1.0.0" + }, + "bin": { + "latest-version": "cli.js" + }, + "engines": { + "node": ">=0.10.0" } }, - "lazy-cache": { + "node_modules/lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", + "engines": { + "node": ">=0.10.0" + } }, - "lodash": { + "node_modules/lodash": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==" }, - "lodash._arrayeach": { + "node_modules/lodash._arrayeach": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", - "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=" + "integrity": "sha512-Mn7HidOVcl3mkQtbPsuKR0Fj0N6Q6DQB77CtYncZcJc0bx5qv2q4Gl6a0LC1AN+GSxpnBDNnK3CKEm9XNA4zqQ==" }, - "lodash._baseassign": { + "node_modules/lodash._baseassign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", - "requires": { + "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", + "dependencies": { "lodash._basecopy": "^3.0.0", "lodash.keys": "^3.0.0" } }, - "lodash._basecopy": { + "node_modules/lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" + "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==" }, - "lodash._baseeach": { + "node_modules/lodash._baseeach": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash._baseeach/-/lodash._baseeach-3.0.4.tgz", - "integrity": "sha1-z4cGVyyhROjZ11InyZDamC+TKvM=", - "requires": { + "integrity": "sha512-IqUZ9MQo2UT1XPGuBntInqTOlc+oV+bCo0kMp+yuKGsfvRSNgUW0YjWVZUrG/gs+8z/Eyuc0jkJjOBESt9BXxg==", + "dependencies": { "lodash.keys": "^3.0.0" } }, - "lodash._bindcallback": { + "node_modules/lodash._bindcallback": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=" + "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==" }, - "lodash._createassigner": { + "node_modules/lodash._createassigner": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", - "integrity": "sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=", - "requires": { + "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", + "dependencies": { "lodash._bindcallback": "^3.0.0", "lodash._isiterateecall": "^3.0.0", "lodash.restparam": "^3.0.0" } }, - "lodash._getnative": { + "node_modules/lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==" }, - "lodash._isiterateecall": { + "node_modules/lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" + "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==" }, - "lodash.assign": { + "node_modules/lodash.assign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", - "integrity": "sha1-POnwI0tLIiPilrj6CsH+6OvKZPo=", - "requires": { + "integrity": "sha512-/VVxzgGBmbphasTg51FrztxQJ/VgAUpol6zmJuSVSGcNg4g7FA4z7rQV8Ovr9V3vFBNWZhvKWHfpAytjTVUfFA==", + "dependencies": { "lodash._baseassign": "^3.0.0", "lodash._createassigner": "^3.0.0", "lodash.keys": "^3.0.0" } }, - "lodash.defaults": { + "node_modules/lodash.defaults": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-3.1.2.tgz", - "integrity": "sha1-xzCLGNv4vJNy1wGnNJPGEZK9Liw=", - "requires": { + "integrity": "sha512-X7135IXFQt5JDFnYxOVAzVz+kFvwDn3N8DJYf+nrz/mMWEuSu7+OL6rWqsk3+VR1T4TejFCSu5isBJOLSID2bg==", + "dependencies": { "lodash.assign": "^3.0.0", "lodash.restparam": "^3.0.0" } }, - "lodash.foreach": { + "node_modules/lodash.foreach": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-3.0.3.tgz", - "integrity": "sha1-b9fvt5aRrs1n/erCdhyY5wHWw5o=", - "requires": { + "integrity": "sha512-PA7Lp7pe2HMJBoB1vELegEIF3waUFnM0fWDKJVYolwZ4zHh6WTmnq0xmzfQksD66gx2quhDNyBdyaE2T8/DP3Q==", + "dependencies": { "lodash._arrayeach": "^3.0.0", "lodash._baseeach": "^3.0.0", "lodash._bindcallback": "^3.0.0", "lodash.isarray": "^3.0.0" } }, - "lodash.isarguments": { + "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" }, - "lodash.isarray": { + "node_modules/lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==" }, - "lodash.keys": { + "node_modules/lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "requires": { + "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", + "dependencies": { "lodash._getnative": "^3.0.0", "lodash.isarguments": "^3.0.0", "lodash.isarray": "^3.0.0" } }, - "lodash.restparam": { + "node_modules/lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" + "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==" }, - "longest": { + "node_modules/longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "requires": { - "mime-db": "1.44.0" + "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", + "engines": { + "node": ">=0.10.0" } }, - "minimatch": { + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "ms": { + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "nested-error-stacks": { + "node_modules/nested-error-stacks": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", - "integrity": "sha1-GfYZWRUZ8JZ2mlupqG5u7sgjw88=", - "requires": { + "integrity": "sha512-o32anp9JA7oezPOFSfG2BBXSdHepOm5FpJvwxHWDtfJ3Bg3xdi68S6ijPlEOfUg6quxZWyvJM+8fHk1yMDKspA==", + "dependencies": { "inherits": "~2.0.1" } }, - "nodemon": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", - "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", - "requires": { + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/nodemon": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", + "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", + "dependencies": { "chokidar": "^3.5.2", - "debug": "^3.2.7", + "debug": "^4", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } + "optional": true } } }, - "nopt": { + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "requires": { + "dependencies": { "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" } }, - "normalize-path": { + "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } }, - "nth-check": { + "node_modules/nth-check": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { + "dependencies": { "boolbase": "~1.0.0" } }, - "oauth-sign": { + "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { "wrappy": "1" } }, - "os-homedir": { + "node_modules/os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "engines": { + "node": ">=0.10.0" + } }, - "os-tmpdir": { + "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } }, - "osenv": { + "node_modules/osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { + "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, - "package-json": { + "node_modules/package-json": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-1.2.0.tgz", - "integrity": "sha1-yOysCUInzfdqMWh07QXifMk5oOA=", - "requires": { + "integrity": "sha512-knDtirWWqKVJrLY3gEBLflVvueTMpyjbAwX/9j/EKi2DsjNemp5voS8cyKyGh57SNaMJNhNRZbIaWdneOcLU1g==", + "dependencies": { "got": "^3.2.0", "registry-url": "^3.0.0" - } - }, - "pascal-case": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", - "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", - "requires": { - "no-case": "^3.0.3", - "tslib": "^1.10.0" }, - "dependencies": { - "lower-case": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", - "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", - "requires": { - "tslib": "^1.10.0" - } - }, - "no-case": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", - "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", - "requires": { - "lower-case": "^2.0.1", - "tslib": "^1.10.0" - } - } + "engines": { + "node": ">=0.10.0" } }, - "performance-now": { + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, - "picomatch": { + "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "prepend-http": { + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", + "engines": { + "node": ">=0.10.0" + } }, - "process-nextick-args": { + "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "promise": { + "node_modules/promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "requires": { + "dependencies": { "asap": "~2.0.3" } }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, - "pstree.remy": { + "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } }, - "q": { + "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } }, - "qs": { + "node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } }, - "rc": { + "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { + "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" } }, - "read-all-stream": { + "node_modules/read-all-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", - "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=", - "requires": { + "integrity": "sha512-DI1drPHbmBcUDWrJ7ull/F2Qb8HkwBncVx8/RpKYFSIACYaVRQReISYPdZz/mt1y1+qMCOrfReTopERmaxtP6w==", + "dependencies": { "pinkie-promise": "^2.0.0", "readable-stream": "^2.0.0" }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } + "engines": { + "node": ">=0.10.0" } }, - "readable-stream": { + "node_modules/read-all-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/read-all-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/read-all-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/read-all-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, - "readdirp": { + "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "requires": { + "dependencies": { "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "registry-url": { + "node_modules/registry-url": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "requires": { + "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", + "dependencies": { "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "relateurl": { + "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "repeating": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", - "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", - "requires": { - "is-finite": "^1.0.0" + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" } }, - "request": { + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/repeating": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", + "integrity": "sha512-Nh30JLeMHdoI+AsQ5eblhZ7YlTsM9wiJQe/AHIunlK3KWzvXhXb36IJ7K1IOeRjIOtzMjdUHjwXUFxKJoPTSOg==", + "dependencies": { + "is-finite": "^1.0.0" + }, + "bin": { + "repeating": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", "caseless": "~0.12.0", @@ -1383,95 +1781,130 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" } }, - "right-align": { + "node_modules/right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "requires": { + "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", + "dependencies": { "align-text": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "safe-buffer": { + "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "safer-buffer": { + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "sax": { + "node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "semver-diff": { + "node_modules/semver-diff": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "requires": { - "semver": "^5.0.3" - } - }, - "simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", - "requires": { - "semver": "~7.0.0" - }, + "integrity": "sha512-gL8F8L4ORwsS0+iQ34yCYv///jsOq0ZL7WP55d1HnJ32o7tyFYEFQZQA22mrLIacZdU6xecaBBZ+uEiffGNyXw==", "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } + "semver": "^5.0.3" + }, + "engines": { + "node": ">=0.10.0" } }, - "slide": { + "node_modules/semver-diff/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slide": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "engines": { + "node": "*" } }, - "sprintf-js": { + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", @@ -1481,49 +1914,70 @@ "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" } }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + "node_modules/stream-shift": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.2.tgz", + "integrity": "sha512-rV4Bovi9xx0BFzOb/X0B2GqoIjvqPCttZdu0Wgtx2Dxkj7ETyWl9gmqJ4EutWRLvtZWm8dxE+InQZX1IryZn/w==" }, - "string-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", - "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=", - "requires": { - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { + "node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" + "node_modules/string-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", + "integrity": "sha512-MNCACnufWUf3pQ57O5WTBMkKhzYIaKEcUioO0XHrTMafrbBaNk4IyDOLHBv5xbXO0jLLdsYWeFjpjG2hVHRDtw==", + "dependencies": { + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "strip-json-comments": { + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } }, - "supports-color": { + "node_modules/supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "engines": { + "node": ">=0.8.0" + } }, - "svgo": { + "node_modules/svgo": { "version": "0.6.6", "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.6.6.tgz", - "integrity": "sha1-s0CIkDbyD5tEdUMHfQ9Vc+0ETAg=", - "requires": { + "integrity": "sha512-C5A1r5SjFesNoKsmc+kWBxmB04iBGH2D/nFy8HJaME9+SyZKcmqcN8QG+GwxIc7D2+JWhaaW7uaM9+XwfplTEQ==", + "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", + "dependencies": { "coa": "~1.0.1", "colors": "~1.1.2", "csso": "~2.0.0", @@ -1531,107 +1985,149 @@ "mkdirp": "~0.5.1", "sax": "~1.2.1", "whet.extend": "~0.9.9" - } - }, - "terser": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", - "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=0.10.0" } }, - "then-fs": { + "node_modules/terser": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", + "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/then-fs": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/then-fs/-/then-fs-2.0.0.tgz", - "integrity": "sha1-cveS3Z0xcFqRrhnr/Piz+WjIHaI=", - "requires": { + "integrity": "sha512-5ffcBcU+vFUCYDNi/o507IqjqrTkuGsLVZ1Fp50hwgZRY7ufVFa9jFfTy5uZ2QnSKacKigWKeaXkOqLa4DsjLw==", + "dependencies": { "promise": ">=3.2 <8" } }, - "timed-out": { + "node_modules/timed-out": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", - "integrity": "sha1-84sK6B03R9YoAB9B2vxlKs5nHAo=" + "integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ==", + "engines": { + "node": ">=0.10.0" + } }, - "to-regex-range": { + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { + "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "touch": { + "node_modules/touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "requires": { + "dependencies": { "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "tough-cookie": { + "node_modules/tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { + "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" } }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "tunnel-agent": { + "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" } }, - "tweetnacl": { + "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" }, - "uglify-js": { + "node_modules/uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "requires": { + "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", + "dependencies": { "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", "yargs": "~3.10.0" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + }, + "optionalDependencies": { + "uglify-to-browserify": "~1.0.0" } }, - "uglify-to-browserify": { + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uglify-to-browserify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", "optional": true }, - "undefsafe": { + "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" }, - "update-notifier": { + "node_modules/update-notifier": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-0.5.0.tgz", - "integrity": "sha1-B7XcIGazYnqztPUwEw9+3doHpMw=", - "requires": { + "integrity": "sha512-zOGOlUKDAgDlLHLv7Oiszz3pSj8fKlSJ3i0u49sEakjXUEVJ6DMjo/Mh/B6mg2eOALvRTJkd0kbChcipQoYCng==", + "dependencies": { "chalk": "^1.0.0", "configstore": "^1.0.0", "is-npm": "^1.0.0", @@ -1639,89 +2135,125 @@ "repeating": "^1.1.2", "semver-diff": "^2.0.0", "string-length": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { "punycode": "^2.1.0" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "uuid": { + "node_modules/uuid": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } }, - "verror": { + "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, - "whet.extend": { + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/whet.extend": { "version": "0.9.9", "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", - "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=" + "integrity": "sha512-mmIPAft2vTgEILgPeZFqE/wWh24SEsR/k+N9fJ3Jxrz44iDFy9aemCxdksfURSHYFCLmvs/d/7Iso5XjPpNfrA==", + "engines": { + "node": ">=0.6.0" + } }, - "window-size": { + "node_modules/window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", + "engines": { + "node": ">= 0.8.0" + } }, - "wordwrap": { + "node_modules/wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", + "engines": { + "node": ">=0.4.0" + } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "write-file-atomic": { + "node_modules/write-file-atomic": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", - "requires": { + "integrity": "sha512-SdrHoC/yVBPpV0Xq/mUZQIpW2sWXAShb/V4pomcJXh92RuaO+f3UTWItiR3Px+pLnV2PvC2/bfn5cwr5X6Vfxw==", + "dependencies": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", "slide": "^1.1.5" } }, - "xdg-basedir": { + "node_modules/xdg-basedir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz", - "integrity": "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=", - "requires": { + "integrity": "sha512-NF1pPn594TaRSUO/HARoB4jK8I+rWgcpVlpQCK6/6o5PHyLUt2CSiDrpUZbQ6rROck+W2EwF8mBJcTs+W98J9w==", + "dependencies": { "os-homedir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "yargs": { + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "requires": { + "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", + "dependencies": { "camelcase": "^1.0.2", "cliui": "^2.1.0", "decamelize": "^1.0.0", "window-size": "0.1.0" } }, - "zlib": { + "node_modules/zlib": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/zlib/-/zlib-1.0.5.tgz", - "integrity": "sha1-bnyXL8NxxkWmr7A6sUdp3vEU/MA=" + "integrity": "sha512-40fpE2II+Cd3k8HWTWONfeKE2jL+P42iWJ1zzps5W51qcTsOUKM5Q5m2PFb0CLxlmFAaUuUdJGc3OfZy947v0w==", + "hasInstallScript": true, + "engines": { + "node": ">=0.2.0" + } } } } diff --git a/package.json b/package.json index 68bd16b82..f490f7635 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ }, "scripts": { "build": "node tools/cdata.js", + "test": "node --test", "dev": "nodemon -e js,html,htm,css,png,jpg,gif,ico,js -w tools/ -w wled00/data/ -x node tools/cdata.js" }, "repository": { @@ -22,10 +23,10 @@ }, "homepage": "https://github.com/Aircoookie/WLED#readme", "dependencies": { - "clean-css": "^4.2.3", - "html-minifier-terser": "^5.1.1", + "clean-css": "^5.3.3", + "html-minifier-terser": "^7.2.0", "inliner": "^1.13.1", - "nodemon": "^2.0.20", + "nodemon": "^3.0.2", "zlib": "^1.0.5" } } diff --git a/platformio.ini b/platformio.ini index 1170e3f69..4fc858e2a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,39 +9,8 @@ # (use `platformio_override.ini` when building for your own board; see `platformio_override.ini.sample` for an example) # ------------------------------------------------------------------------------ -# CI binaries -; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment -default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi - -# Release binaries -; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB - -# Build everything -; default_envs = esp32dev, esp8285_4CH_MagicHome, codm-controller-0_6-rev2, codm-controller-0_6, esp32s2_saola, d1_mini_5CH_Shojo_PCB, d1_mini, sp501e, nodemcuv2, esp32_eth, anavi_miracle_controller, esp07, esp01_1m_full, m5atom, h803wf, d1_mini_ota, heltec_wifi_kit_8, esp8285_H801, d1_mini_debug, wemos_shield_esp32, elekstube_ips - -# Single binaries (uncomment your board) -; default_envs = elekstube_ips -; default_envs = nodemcuv2 -; default_envs = esp8266_2m -; default_envs = esp01_1m_full -; default_envs = esp07 -; default_envs = d1_mini -; default_envs = heltec_wifi_kit_8 -; default_envs = h803wf -; default_envs = d1_mini_debug -; default_envs = d1_mini_ota -; default_envs = esp32dev -; default_envs = esp8285_4CH_MagicHome -; default_envs = esp8285_H801 -; default_envs = d1_mini_5CH_Shojo_PCB -; default_envs = wemos_shield_esp32 -; default_envs = m5atom -; default_envs = esp32_eth -; default_envs = esp32dev_qio80 -; default_envs = esp32_eth_ota1mapp -; default_envs = esp32s2_saola -; default_envs = esp32c3dev -; default_envs = lolin_s2_mini +# CI/release binaries +default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi, esp32_wrover src_dir = ./wled00 data_dir = ./wled00/data @@ -60,9 +29,9 @@ extra_configs = arduino_core_2_6_3 = espressif8266@2.3.3 arduino_core_2_7_4 = espressif8266@2.6.2 arduino_core_3_0_0 = espressif8266@3.0.0 -arduino_core_3_2_0 = espressif8266@3.2.0 -arduino_core_4_1_0 = espressif8266@4.1.0 -arduino_core_3_1_2 = espressif8266@4.2.0 +arduino_core_3_0_2 = espressif8266@3.2.0 +arduino_core_3_1_0 = espressif8266@4.1.0 +arduino_core_3_1_2 = espressif8266@4.2.1 # Development platforms arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop @@ -132,12 +101,7 @@ build_flags = -D DECODE_SONY=true -D DECODE_SAMSUNG=true -D DECODE_LG=true - ;-Dregister= # remove warnings in C++17 due to use of deprecated register keyword by the FastLED library ;; warning: this breaks framework code on ESP32-C3 and ESP32-S2 -DWLED_USE_MY_CONFIG - ; -D USERMOD_SENSORSTOMQTT - #For ADS1115 sensor uncomment following - ; -D USERMOD_ADS1115 - ; -D USERMOD_ANIMARTRIX build_unflags = @@ -165,10 +129,8 @@ extra_scripts = framework = arduino board_build.flash_mode = dout monitor_speed = 115200 -# slow upload speed (comment this out with a ';' when building for development use) +# slow upload speed but most compatible (use platformio_override.ini to use faster speed) upload_speed = 115200 -# fast upload speed (remove ';' when building for development use) -; upload_speed = 921600 # ------------------------------------------------------------------------------ # LIBRARIES: required dependencies @@ -183,28 +145,34 @@ lib_deps = IRremoteESP8266 @ 2.8.2 makuna/NeoPixelBus @ 2.7.5 https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.7 + # for I2C interface + ;Wire # ESP-NOW library (includes mandatory QuickDebug library) - ; gmag11/QuickESPNow @ 0.6.2 + ;gmag11/QuickESPNow @ 0.6.2 https://github.com/blazoncek/QuickESPNow.git#optional-debug #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line #TFT_eSPI #For compatible OLED display uncomment following - #U8g2 #@ ~2.33.15 + #olikraus/U8g2 #@ ~2.33.15 #For Dallas sensor uncomment following - #OneWire @ ~2.3.7 + #paulstoffregen/OneWire @ ~2.3.8 #For BME280 sensor uncomment following #BME280 @ ~3.0.0 - ; adafruit/Adafruit BMP280 Library @ 2.1.0 - ; adafruit/Adafruit CCS811 Library @ 1.0.4 - ; adafruit/Adafruit Si7021 Library @ 1.4.0 + ;adafruit/Adafruit BMP280 Library @ 2.1.0 + ;adafruit/Adafruit CCS811 Library @ 1.0.4 + ;adafruit/Adafruit Si7021 Library @ 1.4.0 #For ADS1115 sensor uncomment following - ; adafruit/Adafruit BusIO @ 1.13.2 - ; adafruit/Adafruit ADS1X15 @ 2.4.0 + ;adafruit/Adafruit BusIO @ 1.13.2 + ;adafruit/Adafruit ADS1X15 @ 2.4.0 #For MPU6050 IMU uncomment follwoing - ; electroniccats/MPU6050 @1.0.1 - # For -D USERMOD_ANIMARTRIX - # CC BY-NC 3.0 licensed effects by Stefan Petrick, include this usermod only if you accept the terms! - ; https://github.com/netmindz/animartrix.git#18bf17389e57c69f11bc8d04ebe1d215422c7fb7 + ;electroniccats/MPU6050 @1.0.1 + # For -D USERMOD_ANIMARTRIX + # CC BY-NC 3.0 licensed effects by Stefan Petrick, include this usermod only if you accept the terms! + ;https://github.com/netmindz/animartrix.git#18bf17389e57c69f11bc8d04ebe1d215422c7fb7 + # SHT85 + ;robtillaart/SHT85@~0.3.3 + # Audioreactive usermod + ;https://github.com/kosme/arduinoFFT#develop @ ^1.9.2 extra_scripts = ${scripts_defaults.extra_scripts} @@ -280,6 +248,7 @@ lib_deps = ;; generic definitions for all ESP32-S2 boards platform = espressif32@5.3.0 platform_packages = +default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv build_flags = -g -DARDUINO_ARCH_ESP32 -DARDUINO_ARCH_ESP32S2 @@ -290,7 +259,6 @@ build_flags = -g -DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 ! ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; ARDUINO_USB_CDC_ON_BOOT - lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} @@ -308,7 +276,6 @@ build_flags = -g -DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3 ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; ARDUINO_USB_CDC_ON_BOOT - lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} @@ -366,44 +333,6 @@ build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_D ; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 7064 bytes FLASH and 975 bytes RAM lib_deps = ${esp8266.lib_deps} -[env:esp07] -board = esp07 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -lib_deps = ${esp8266.lib_deps} - -[env:d1_mini] -board = d1_mini -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -upload_speed = 921600 -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -lib_deps = ${esp8266.lib_deps} -monitor_filters = esp8266_exception_decoder - -[env:heltec_wifi_kit_8] -board = d1_mini -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -lib_deps = ${esp8266.lib_deps} - -[env:h803wf] -board = d1_mini -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D LEDPIN=1 -D WLED_DISABLE_INFRARED -lib_deps = ${esp8266.lib_deps} - [env:esp32dev] board = esp32dev platform = ${esp32.platform} @@ -428,33 +357,6 @@ board_build.partitions = ${esp32.default_partitions} ; board_build.f_flash = 80000000L ; board_build.flash_mode = dio -[env:esp32dev_qio80] -board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_qio80 #-D WLED_DISABLE_BROWNOUT_DET -lib_deps = ${esp32.lib_deps} -monitor_filters = esp32_exception_decoder -board_build.partitions = ${esp32.default_partitions} -board_build.f_flash = 80000000L -board_build.flash_mode = qio - -[env:esp32dev_V4_dio80] -;; experimental ESP32 env using ESP-IDF V4.4.x -;; Warning: this build environment is not stable!! -;; please erase your device before installing. -board = esp32dev -platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_V4_qio80 #-D WLED_DISABLE_BROWNOUT_DET -lib_deps = ${esp32_idf_V4.lib_deps} -monitor_filters = esp32_exception_decoder -board_build.partitions = ${esp32_idf_V4.default_partitions} -board_build.f_flash = 80000000L -board_build.flash_mode = dio - [env:esp32_eth] board = esp32-poe platform = ${esp32.platform} @@ -466,19 +368,18 @@ build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D lib_deps = ${esp32.lib_deps} board_build.partitions = ${esp32.default_partitions} -[env:esp32s2_saola] -board = esp32-s2-saola-1 -platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip -platform_packages = -framework = arduino -board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv +[env:esp32_wrover] +platform = ${esp32.platform} +board = ttgo-t7-v14-mini32 +board_build.f_flash = 80000000L board_build.flash_mode = qio -upload_speed = 460800 +board_build.partitions = ${esp32.default_partitions} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=S2_saola - ;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work - -DARDUINO_USB_CDC_ON_BOOT=1 -lib_deps = ${esp32s2.lib_deps} +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_WROVER + -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue + -D WLED_USE_PSRAM + -D LEDPIN=25 +lib_deps = ${esp32.lib_deps} [env:esp32c3dev] extends = esp32c3 @@ -535,95 +436,24 @@ board_build.f_flash = 80000000L board_build.flash_mode = qio monitor_filters = esp32_exception_decoder -[env:esp32s3dev_8MB_PSRAM_qspi] -;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi) -extends = env:esp32s3dev_8MB_PSRAM_opi -;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860 -board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support -board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB - -[env:esp8285_4CH_MagicHome] -board = esp8285 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_1m128k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -lib_deps = ${esp8266.lib_deps} - -[env:esp8285_H801] -board = esp8285 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_1m128k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA -lib_deps = ${esp8266.lib_deps} - -[env:d1_mini_5CH_Shojo_PCB] -board = d1_mini -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_USE_SHOJO_PCB -lib_deps = ${esp8266.lib_deps} - -# ------------------------------------------------------------------------------ -# DEVELOPMENT BOARDS -# ------------------------------------------------------------------------------ - -[env:d1_mini_debug] -board = d1_mini -build_type = debug -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} ${common.debug_flags} -lib_deps = ${esp8266.lib_deps} - -[env:d1_mini_ota] -board = d1_mini -upload_protocol = espota -# exchange for your WLED IP -upload_port = "10.10.1.27" -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -lib_deps = ${esp8266.lib_deps} - -[env:anavi_miracle_controller] -board = d1_mini -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D LEDPIN=12 -D IRPIN=-1 -D RLYPIN=2 -lib_deps = ${esp8266.lib_deps} - [env:lolin_s2_mini] platform = ${esp32s2.platform} platform_packages = ${esp32s2.platform_packages} board = lolin_s2_mini board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv -build_unflags = ${common.build_unflags} #-DARDUINO_USB_CDC_ON_BOOT=1 +;board_build.flash_mode = qio +;board_build.f_flash = 80000000L +build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2 -DBOARD_HAS_PSRAM - -DARDUINO_USB_CDC_ON_BOOT=1 # try disabling and enabling unflag above in case of board-specific issues, will disable Serial + -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DLOLIN_WIFI_FIX ; seems to work much better with this -D WLED_USE_PSRAM - ; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 6792 bytes FLASH -D WLED_WATCHDOG_TIMEOUT=0 -D CONFIG_ASYNC_TCP_USE_WDT=0 -D LEDPIN=16 - -D BTNPIN=18 - -D RLYPIN=9 - -D IRPIN=7 -D HW_PIN_SCL=35 -D HW_PIN_SDA=33 -D HW_PIN_CLOCKSPI=7 @@ -631,188 +461,3 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME= -D HW_PIN_MISOSPI=9 ; -D STATUSLED=15 lib_deps = ${esp32s2.lib_deps} - -# ------------------------------------------------------------------------------ -# custom board configurations -# ------------------------------------------------------------------------------ - -[env:esp32c3dev_2MB] -;; for ESP32-C3 boards with 2MB flash (instead of 4MB). -;; this board need a specific partition file. OTA not possible. -extends = esp32c3 -platform = ${esp32c3.platform} -platform_packages = ${esp32c3.platform_packages} -board = esp32-c3-devkitm-1 -build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3 - -D WLED_WATCHDOG_TIMEOUT=0 - -D WLED_DISABLE_OTA - ; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB - -DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip -build_unflags = ${common.build_unflags} -upload_speed = 115200 -lib_deps = ${esp32c3.lib_deps} -board_build.partitions = tools/WLED_ESP32_2MB_noOTA.csv -board_build.flash_mode = dio - -[env:wemos_shield_esp32] -board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} -upload_speed = 460800 -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} - -D LEDPIN=16 - -D RLYPIN=19 - -D BTNPIN=17 - -D IRPIN=18 - -D UWLED_USE_MY_CONFIG - -D USERMOD_DALLASTEMPERATURE - -D USERMOD_FOUR_LINE_DISPLAY - -D TEMPERATURE_PIN=23 - -D USE_ALT_DISPlAY ; new versions of USERMOD_FOUR_LINE_DISPLAY and USERMOD_ROTARY_ENCODER_UI - -D USERMOD_AUDIOREACTIVE -lib_deps = ${esp32.lib_deps} - OneWire@~2.3.5 - olikraus/U8g2 @ ^2.28.8 - https://github.com/blazoncek/arduinoFFT.git -board_build.partitions = ${esp32.default_partitions} - -[env:m5atom] -board = esp32dev -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39 -lib_deps = ${esp32.lib_deps} -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} -board_build.partitions = ${esp32.default_partitions} - -[env:sp501e] -board = esp_wroom_02 -platform = ${common.platform_wled_default} -board_build.ldscript = ${common.ldscript_2m512k} -build_flags = ${common.build_flags_esp8266} -D LEDPIN=3 -D BTNPIN=1 -lib_deps = ${esp8266.lib_deps} - -[env:sp511e] -board = esp_wroom_02 -platform = ${common.platform_wled_default} -board_build.ldscript = ${common.ldscript_2m512k} -build_flags = ${common.build_flags_esp8266} -D LEDPIN=3 -D BTNPIN=2 -D IRPIN=5 -D WLED_MAX_BUTTONS=3 -lib_deps = ${esp8266.lib_deps} - -[env:Athom_RGBCW] ;7w and 5w(GU10) bulbs -board = esp8285 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_2m512k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5 - -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -lib_deps = ${esp8266.lib_deps} - - -[env:Athom_15w_RGBCW] ;15w bulb -board = esp8285 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_2m512k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13 - -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT -lib_deps = ${esp8266.lib_deps} - - -[env:Athom_3Pin_Controller] ;small controller with only data -board = esp8285 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_2m512k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=0 -D RLYPIN=-1 -D LEDPIN=1 -D WLED_DISABLE_INFRARED -lib_deps = ${esp8266.lib_deps} - - -[env:Athom_4Pin_Controller] ; With clock and data interface -board = esp8285 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_2m512k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=0 -D RLYPIN=12 -D LEDPIN=1 -D WLED_DISABLE_INFRARED -lib_deps = ${esp8266.lib_deps} - - -[env:Athom_5Pin_Controller] ;Analog light strip controller -board = esp8285 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_2m512k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=0 -D RLYPIN=-1 DATA_PINS=4,12,14,13 -D WLED_DISABLE_INFRARED -lib_deps = ${esp8266.lib_deps} - - -[env:MY9291] -board = esp01_1m -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_1m128k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA -D USERMOD_MY9291 -lib_deps = ${esp8266.lib_deps} - -# ------------------------------------------------------------------------------ -# codm pixel controller board configurations -# codm-controller-0_6 can also be used for the TYWE3S controller -# ------------------------------------------------------------------------------ - -[env:codm-controller-0_6] -board = esp_wroom_02 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_2m512k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -lib_deps = ${esp8266.lib_deps} - -[env:codm-controller-0_6-rev2] -board = esp_wroom_02 -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -lib_deps = ${esp8266.lib_deps} - -# ------------------------------------------------------------------------------ -# EleksTube-IPS -# ------------------------------------------------------------------------------ -[env:elekstube_ips] -board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} -upload_speed = 921600 -build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED - -D USERMOD_RTC - -D USERMOD_ELEKSTUBE_IPS - -D LEDPIN=12 - -D RLYPIN=27 - -D BTNPIN=34 - -D DEFAULT_LED_COUNT=6 - # Display config - -D ST7789_DRIVER - -D TFT_WIDTH=135 - -D TFT_HEIGHT=240 - -D CGRAM_OFFSET - -D TFT_SDA_READ - -D TFT_MOSI=23 - -D TFT_SCLK=18 - -D TFT_DC=25 - -D TFT_RST=26 - -D SPI_FREQUENCY=40000000 - -D USER_SETUP_LOADED -monitor_filters = esp32_exception_decoder -lib_deps = - ${esp32.lib_deps} - TFT_eSPI @ ^2.3.70 -board_build.partitions = ${esp32.default_partitions} diff --git a/platformio_override.ini.sample b/platformio_override.ini.sample deleted file mode 100644 index d6ea5d964..000000000 --- a/platformio_override.ini.sample +++ /dev/null @@ -1,65 +0,0 @@ -# Example PlatformIO Project Configuration Override -# ------------------------------------------------------------------------------ -# Copy to platformio_override.ini to activate overrides -# ------------------------------------------------------------------------------ -# Please visit documentation: https://docs.platformio.org/page/projectconf.html - -[platformio] -default_envs = WLED_tasmota_1M - -[env:WLED_tasmota_1M] -board = esp01_1m -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -board_build.ldscript = ${common.ldscript_1m128k} -lib_deps = ${esp8266.lib_deps} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp8266} -; ********************************************************************* -; *** Use custom settings from file my_config.h - -DWLED_USE_MY_CONFIG -; ********************************************************************* -; -; -; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above. -; -; disable specific features -; -D WLED_DISABLE_OTA -; -D WLED_DISABLE_ALEXA -; -D WLED_DISABLE_HUESYNC -; -D WLED_DISABLE_INFRARED -; -D WLED_DISABLE_WEBSOCKETS -; PIN defines - uncomment and change, if needed: -; -D LEDPIN=2 -; -D BTNPIN=0 -; -D TOUCHPIN=T0 -; -D IRPIN=4 -; -D RLYPIN=12 -; -D RLYMDE=1 -; digital LED strip types - uncomment only one ! - this will disable WS281x / SK681x support -; -D USE_APA102 -; -D USE_WS2801 -; -D USE_LPD8806 -; PIN defines for 2 wire LEDs - -D CLKPIN=0 - -D DATAPIN=2 -; to drive analog LED strips (aka 5050) hardware configuration is no longer necessary -; configure the settings in the UI as follows (hard): -; for the Magic Home LED Controller use PWM pins 5,12,13,15 -; for the H801 controller use PINs 15,13,12,14 (W2 = 04) -; for the BW-LT11 controller use PINs 12,4,14,5 -; -; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name -; -D SERVERNAME="\"WLED\"" -; -; set the number of LEDs -; -D DEFAULT_LED_COUNT=30 -; -; set milliampere limit when using ESP pin to power leds -; -D ABL_MILLIAMPS_DEFAULT=850 -; -; enable IR by setting remote type -; -D IRTYPE=0 ;0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote -; -; set default color order of your led strip -; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini new file mode 100644 index 000000000..29f5c6b57 --- /dev/null +++ b/platformio_override.sample.ini @@ -0,0 +1,495 @@ +# Example PlatformIO Project Configuration Override +# ------------------------------------------------------------------------------ +# Copy to platformio_override.ini to activate overrides +# ------------------------------------------------------------------------------ +# Please visit documentation: https://docs.platformio.org/page/projectconf.html + +[platformio] +default_envs = WLED_tasmota_1M # define as many as you need + +#---------- +# SAMPLE +#---------- +[env:WLED_tasmota_1M] +extends = env:esp01_1m_full # when you want to extend the existing environment (define only updated options) +; board = esp01_1m # uncomment when ou need different board +; platform = ${common.platform_wled_default} # uncomment and change when you want particular platform +; platform_packages = ${common.platform_packages} +; board_build.ldscript = ${common.ldscript_1m128k} +; upload_speed = 921600 # fast upload speed (remove ';' if your board supports fast upload speed) +# Sample libraries used for various usermods. Uncomment when using particular usermod. +lib_deps = ${esp8266.lib_deps} +; olikraus/U8g2 # @~2.33.15 +; paulstoffregen/OneWire@~2.3.8 +; adafruit/Adafruit Unified Sensor@^1.1.4 +; adafruit/DHT sensor library@^1.4.1 +; adafruit/Adafruit BME280 Library@^2.2.2 +; Wire +; robtillaart/SHT85@~0.3.3 +; gmag11/QuickESPNow ;@ 0.6.2 +; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library +; https://github.com/kosme/arduinoFFT#develop @ 1.9.2+sha.419d7b0 ;; used for USERMOD_AUDIOREACTIVE - using "known working" hash +; build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} +; +; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above. +; +; disable specific features +; -D WLED_DISABLE_OTA +; -D WLED_DISABLE_ALEXA +; -D WLED_DISABLE_HUESYNC +; -D WLED_DISABLE_LOXONE +; -D WLED_DISABLE_INFRARED +; -D WLED_DISABLE_WEBSOCKETS +; -D WLED_DISABLE_MQTT +; -D WLED_DISABLE_ADALIGHT +; -D WLED_DISABLE_2D +; -D WLED_DISABLE_PXMAGIC +; -D WLED_DISABLE_ESPNOW +; -D WLED_DISABLE_BROWNOUT_DET +; +; PIN defines - uncomment and change, if needed: +; -D LEDPIN=2 +; or use this for multiple outputs +; -D DATA_PINS=1,3 +; -D BTNPIN=0 +; -D IRPIN=4 +; -D RLYPIN=12 +; -D RLYMDE=1 +; -D LED_BUILTIN=2 # GPIO of built-in LED +; +; Limit max buses +; -D WLED_MAX_BUSSES=2 +; +; Configure default WiFi +; -D CLIENT_SSID='"MyNetwork"' +; -D CLIENT_PASS='"Netw0rkPassw0rd"' +; +; Configure and use Ethernet +; -D WLED_USE_ETHERNET +; -D WLED_ETH_DEFAULT=5 +; do not use pins 5, (16,) 17, 18, 19, 21, 22, 23, 25, 26, 27 for anything but ethernet +; -D PHY_ADDR=0 -D ETH_PHY_POWER=5 -D ETH_PHY_MDC=23 -D ETH_PHY_MDIO=18 +; -D ETH_CLK_MODE=ETH_CLOCK_GPIO17_OUT +; +; NTP time configuration +; -D WLED_NTP_ENABLED=true +; -D WLED_TIMEZONE=2 +; -D WLED_LAT=48.86 +; -D WLED_LON=2.33 +; +; Use Watchdog timer with 10s guard +; -D WLED_WATCHDOG_TIMEOUT=10 +; +; Create debug build (with remote debug) +; -D WLED_DEBUG +; -D WLED_DEBUG_HOST='"192.168.0.100"' +; -D WLED_DEBUG_PORT=7868 +; +; Use Autosave usermod and set it to do save after 90s +; -D USERMOD_AUTO_SAVE +; -D AUTOSAVE_AFTER_SEC=90 +; +; Use 4 Line Display usermod with SPI display +; -D USERMOD_FOUR_LINE_DISPLAY +; -D USE_ALT_DISPlAY # mandatory +; -DFLD_SPI_DEFAULT +; -D FLD_TYPE=SSD1306_SPI64 +; -D FLD_PIN_CLOCKSPI=14 +; -D FLD_PIN_DATASPI=13 +; -D FLD_PIN_DC=26 +; -D FLD_PIN_CS=15 +; -D FLD_PIN_RESET=27 +; +; Use Rotary encoder usermod (in conjunction with 4LD) +; -D USERMOD_ROTARY_ENCODER_UI +; -D ENCODER_DT_PIN=5 +; -D ENCODER_CLK_PIN=18 +; -D ENCODER_SW_PIN=19 +; +; Use Dallas DS18B20 temperature sensor usermod and configure it to use GPIO13 +; -D USERMOD_DALLASTEMPERATURE +; -D TEMPERATURE_PIN=13 +; +; Use Multi Relay usermod and configure it to use 6 relays and appropriate GPIO +; -D USERMOD_MULTI_RELAY +; -D MULTI_RELAY_MAX_RELAYS=6 +; -D MULTI_RELAY_PINS=12,23,22,21,24,25 +; +; Use PIR sensor usermod and configure it to use GPIO4 and timer of 60s +; -D USERMOD_PIRSWITCH +; -D PIR_SENSOR_PIN=4 +; -D PIR_SENSOR_OFF_SEC=60 +; +; Use Audioreactive usermod and configure I2S microphone +; -D USERMOD_AUDIOREACTIVE +; -D UM_AUDIOREACTIVE_USE_NEW_FFT +; -D AUDIOPIN=-1 +; -D DMTYPE=1 # 0-analog/disabled, 1-I2S generic, 2-ES7243, 3-SPH0645, 4-I2S+mclk, 5-I2S PDM +; -D I2S_SDPIN=36 +; -D I2S_WSPIN=23 +; -D I2S_CKPIN=19 +; +; Use PWM fan usermod +; -D USERMOD_PWM_FAN +; -D TACHO_PIN=33 +; -D PWM_PIN=32 +; +; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16) +; -D STATUSLED=16 +; +; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name +; -D SERVERNAME="\"WLED\"" +; +; set the number of LEDs +; -D DEFAULT_LED_COUNT=30 +; or this for multiple outputs +; -D PIXEL_COUNTS=30,30 +; +; set milliampere limit when using ESP pin to power leds +; -D ABL_MILLIAMPS_DEFAULT=850 +; +; enable IR by setting remote type +; -D IRTYPE=0 ;0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote +; +; set default color order of your led strip +; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB +; +; use PSRAM if a device (ESP) has one +; -DBOARD_HAS_PSRAM +; -D WLED_USE_PSRAM +; +; configure I2C and SPI interface (for various hardware) +; -D I2CSDAPIN=33 # initialise interface +; -D I2CSCLPIN=35 # initialise interface +; -D HW_PIN_SCL=35 +; -D HW_PIN_SDA=33 +; -D HW_PIN_CLOCKSPI=7 +; -D HW_PIN_DATASPI=11 +; -D HW_PIN_MISOSPI=9 + + + +# ------------------------------------------------------------------------------ +# PRE-CONFIGURED DEVELOPMENT BOARDS AND CONTROLLERS +# ------------------------------------------------------------------------------ + +[env:esp07] +board = esp07 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} +lib_deps = ${esp8266.lib_deps} + +[env:d1_mini] +board = d1_mini +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +upload_speed = 921600 +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} +lib_deps = ${esp8266.lib_deps} +monitor_filters = esp8266_exception_decoder + +[env:heltec_wifi_kit_8] +board = d1_mini +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} +lib_deps = ${esp8266.lib_deps} + +[env:h803wf] +board = d1_mini +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D LEDPIN=1 -D WLED_DISABLE_INFRARED +lib_deps = ${esp8266.lib_deps} + +[env:esp32dev_qio80] +board = esp32dev +platform = ${esp32.platform} +platform_packages = ${esp32.platform_packages} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_qio80 #-D WLED_DISABLE_BROWNOUT_DET +lib_deps = ${esp32.lib_deps} +monitor_filters = esp32_exception_decoder +board_build.partitions = ${esp32.default_partitions} +board_build.f_flash = 80000000L +board_build.flash_mode = qio + +[env:esp32dev_V4_dio80] +;; experimental ESP32 env using ESP-IDF V4.4.x +;; Warning: this build environment is not stable!! +;; please erase your device before installing. +board = esp32dev +platform = ${esp32_idf_V4.platform} +platform_packages = ${esp32_idf_V4.platform_packages} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_V4_qio80 #-D WLED_DISABLE_BROWNOUT_DET +lib_deps = ${esp32_idf_V4.lib_deps} +monitor_filters = esp32_exception_decoder +board_build.partitions = ${esp32_idf_V4.default_partitions} +board_build.f_flash = 80000000L +board_build.flash_mode = dio + +[env:esp32s2_saola] +board = esp32-s2-saola-1 +platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.2/platform-tasmota-espressif32-2.0.2.zip +platform_packages = +framework = arduino +board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv +board_build.flash_mode = qio +upload_speed = 460800 +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=S2_saola + ;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work + -DARDUINO_USB_CDC_ON_BOOT=1 +lib_deps = ${esp32s2.lib_deps} + +[env:esp32s3dev_8MB_PSRAM_qspi] +;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi) +extends = env:esp32s3dev_8MB_PSRAM_opi +;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860 +board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support +board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB + +[env:esp8285_4CH_MagicHome] +board = esp8285 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_1m128k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA +lib_deps = ${esp8266.lib_deps} + +[env:esp8285_H801] +board = esp8285 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_1m128k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_OTA +lib_deps = ${esp8266.lib_deps} + +[env:d1_mini_5CH_Shojo_PCB] +board = d1_mini +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_USE_SHOJO_PCB +lib_deps = ${esp8266.lib_deps} + +[env:d1_mini_debug] +board = d1_mini +build_type = debug +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} ${common.debug_flags} +lib_deps = ${esp8266.lib_deps} + +[env:d1_mini_ota] +board = d1_mini +upload_protocol = espota +# exchange for your WLED IP +upload_port = "10.10.1.27" +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} +lib_deps = ${esp8266.lib_deps} + +[env:anavi_miracle_controller] +board = d1_mini +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D LEDPIN=12 -D IRPIN=-1 -D RLYPIN=2 +lib_deps = ${esp8266.lib_deps} + +[env:esp32c3dev_2MB] +;; for ESP32-C3 boards with 2MB flash (instead of 4MB). +;; this board need a specific partition file. OTA not possible. +extends = esp32c3 +platform = ${esp32c3.platform} +platform_packages = ${esp32c3.platform_packages} +board = esp32-c3-devkitm-1 +build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3 + -D WLED_WATCHDOG_TIMEOUT=0 + -D WLED_DISABLE_OTA + ; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB + -DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip +build_unflags = ${common.build_unflags} +upload_speed = 115200 +lib_deps = ${esp32c3.lib_deps} +board_build.partitions = tools/WLED_ESP32_2MB_noOTA.csv +board_build.flash_mode = dio + +[env:wemos_shield_esp32] +board = esp32dev +platform = ${esp32.platform} +platform_packages = ${esp32.platform_packages} +upload_speed = 460800 +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp32} + -D LEDPIN=16 + -D RLYPIN=19 + -D BTNPIN=17 + -D IRPIN=18 + -D UWLED_USE_MY_CONFIG + -D USERMOD_DALLASTEMPERATURE + -D USERMOD_FOUR_LINE_DISPLAY + -D TEMPERATURE_PIN=23 + -D USE_ALT_DISPlAY ; new versions of USERMOD_FOUR_LINE_DISPLAY and USERMOD_ROTARY_ENCODER_UI + -D USERMOD_AUDIOREACTIVE +lib_deps = ${esp32.lib_deps} + OneWire@~2.3.5 + olikraus/U8g2 @ ^2.28.8 + https://github.com/blazoncek/arduinoFFT.git +board_build.partitions = ${esp32.default_partitions} + +[env:m5atom] +board = esp32dev +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp32} -D LEDPIN=27 -D BTNPIN=39 +lib_deps = ${esp32.lib_deps} +platform = ${esp32.platform} +platform_packages = ${esp32.platform_packages} +board_build.partitions = ${esp32.default_partitions} + +[env:sp501e] +board = esp_wroom_02 +platform = ${common.platform_wled_default} +board_build.ldscript = ${common.ldscript_2m512k} +build_flags = ${common.build_flags_esp8266} -D LEDPIN=3 -D BTNPIN=1 +lib_deps = ${esp8266.lib_deps} + +[env:sp511e] +board = esp_wroom_02 +platform = ${common.platform_wled_default} +board_build.ldscript = ${common.ldscript_2m512k} +build_flags = ${common.build_flags_esp8266} -D LEDPIN=3 -D BTNPIN=2 -D IRPIN=5 -D WLED_MAX_BUTTONS=3 +lib_deps = ${esp8266.lib_deps} + +[env:Athom_RGBCW] ;7w and 5w(GU10) bulbs +board = esp8285 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_2m512k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5 + -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 +lib_deps = ${esp8266.lib_deps} + +[env:Athom_15w_RGBCW] ;15w bulb +board = esp8285 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_2m512k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13 + -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT +lib_deps = ${esp8266.lib_deps} + +[env:Athom_3Pin_Controller] ;small controller with only data +board = esp8285 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_2m512k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=0 -D RLYPIN=-1 -D LEDPIN=1 -D WLED_DISABLE_INFRARED +lib_deps = ${esp8266.lib_deps} + +[env:Athom_4Pin_Controller] ; With clock and data interface +board = esp8285 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_2m512k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=0 -D RLYPIN=12 -D LEDPIN=1 -D WLED_DISABLE_INFRARED +lib_deps = ${esp8266.lib_deps} + +[env:Athom_5Pin_Controller] ;Analog light strip controller +board = esp8285 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_2m512k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 -D BTNPIN=0 -D RLYPIN=-1 DATA_PINS=4,12,14,13 -D WLED_DISABLE_INFRARED +lib_deps = ${esp8266.lib_deps} + +[env:MY9291] +board = esp01_1m +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_1m128k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA -D USERMOD_MY9291 +lib_deps = ${esp8266.lib_deps} + +# ------------------------------------------------------------------------------ +# codm pixel controller board configurations +# codm-controller-0_6 can also be used for the TYWE3S controller +# ------------------------------------------------------------------------------ + +[env:codm-controller-0_6] +board = esp_wroom_02 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_2m512k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} +lib_deps = ${esp8266.lib_deps} + +[env:codm-controller-0_6-rev2] +board = esp_wroom_02 +platform = ${common.platform_wled_default} +platform_packages = ${common.platform_packages} +board_build.ldscript = ${common.ldscript_4m1m} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags_esp8266} +lib_deps = ${esp8266.lib_deps} + +# ------------------------------------------------------------------------------ +# EleksTube-IPS +# ------------------------------------------------------------------------------ +[env:elekstube_ips] +board = esp32dev +platform = ${esp32.platform} +platform_packages = ${esp32.platform_packages} +upload_speed = 921600 +build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED + -D USERMOD_RTC + -D USERMOD_ELEKSTUBE_IPS + -D LEDPIN=12 + -D RLYPIN=27 + -D BTNPIN=34 + -D DEFAULT_LED_COUNT=6 + # Display config + -D ST7789_DRIVER + -D TFT_WIDTH=135 + -D TFT_HEIGHT=240 + -D CGRAM_OFFSET + -D TFT_SDA_READ + -D TFT_MOSI=23 + -D TFT_SCLK=18 + -D TFT_DC=25 + -D TFT_RST=26 + -D SPI_FREQUENCY=40000000 + -D USER_SETUP_LOADED +monitor_filters = esp32_exception_decoder +lib_deps = + ${esp32.lib_deps} + TFT_eSPI @ ^2.3.70 +board_build.partitions = ${esp32.default_partitions} diff --git a/tools/cdata-test.js b/tools/cdata-test.js new file mode 100644 index 000000000..55f068073 --- /dev/null +++ b/tools/cdata-test.js @@ -0,0 +1,205 @@ +'use strict'; + +const assert = require('node:assert'); +const { describe, it, before, after } = require('node:test'); +const fs = require('fs'); +const path = require('path'); +const child_process = require('child_process'); +const util = require('util'); +const execPromise = util.promisify(child_process.exec); + +process.env.NODE_ENV = 'test'; // Set the environment to testing +const cdata = require('./cdata.js'); + +describe('Function', () => { + const testFolderPath = path.join(__dirname, 'testFolder'); + const oldFilePath = path.join(testFolderPath, 'oldFile.txt'); + const newFilePath = path.join(testFolderPath, 'newFile.txt'); + + // Create a temporary file before the test + before(() => { + // Create test folder + if (!fs.existsSync(testFolderPath)) { + fs.mkdirSync(testFolderPath); + } + + // Create an old file + fs.writeFileSync(oldFilePath, 'This is an old file.'); + // Modify the 'mtime' to simulate an old file + const oldTime = new Date(); + oldTime.setFullYear(oldTime.getFullYear() - 1); + fs.utimesSync(oldFilePath, oldTime, oldTime); + + // Create a new file + fs.writeFileSync(newFilePath, 'This is a new file.'); + }); + + // delete the temporary files after the test + after(() => { + fs.rmSync(testFolderPath, { recursive: true }); + }); + + describe('isFileNewerThan', async () => { + it('should return true if the file is newer than the provided time', async () => { + const pastTime = Date.now() - 10000; // 10 seconds ago + assert.strictEqual(cdata.isFileNewerThan(newFilePath, pastTime), true); + }); + + it('should return false if the file is older than the provided time', async () => { + assert.strictEqual(cdata.isFileNewerThan(oldFilePath, Date.now()), false); + }); + + it('should throw an exception if the file does not exist', async () => { + assert.throws(() => { + cdata.isFileNewerThan('nonexistent.txt', Date.now()); + }); + }); + }); + + describe('isAnyFileInFolderNewerThan', async () => { + it('should return true if a file in the folder is newer than the given time', async () => { + const time = fs.statSync(path.join(testFolderPath, 'oldFile.txt')).mtime; + assert.strictEqual(cdata.isAnyFileInFolderNewerThan(testFolderPath, time), true); + }); + + it('should return false if no files in the folder are newer than the given time', async () => { + assert.strictEqual(cdata.isAnyFileInFolderNewerThan(testFolderPath, new Date()), false); + }); + + it('should throw an exception if the folder does not exist', async () => { + assert.throws(() => { + cdata.isAnyFileInFolderNewerThan('nonexistent', new Date()); + }); + }); + }); +}); + +describe('Script', () => { + const folderPath = 'wled00'; + const dataPath = path.join(folderPath, 'data'); + + before(() => { + process.env.NODE_ENV = 'production'; + // Backup files + fs.cpSync("wled00/data", "wled00Backup", { recursive: true }); + fs.cpSync("tools/cdata.js", "cdata.bak.js"); + }); + after(() => { + // Restore backup + fs.rmSync("wled00/data", { recursive: true }); + fs.renameSync("wled00Backup", "wled00/data"); + fs.rmSync("tools/cdata.js"); + fs.renameSync("cdata.bak.js", "tools/cdata.js"); + }); + + // delete all html_*.h files + async function deleteBuiltFiles() { + const files = await fs.promises.readdir(folderPath); + await Promise.all(files.map(file => { + if (file.startsWith('html_') && path.extname(file) === '.h') { + return fs.promises.unlink(path.join(folderPath, file)); + } + })); + } + + // check if html_*.h files were created + async function checkIfBuiltFilesExist() { + const files = await fs.promises.readdir(folderPath); + const htmlFiles = files.filter(file => file.startsWith('html_') && path.extname(file) === '.h'); + assert(htmlFiles.length > 0, 'html_*.h files were not created'); + } + + async function runAndCheckIfBuiltFilesExist() { + await execPromise('node tools/cdata.js'); + await checkIfBuiltFilesExist(); + } + + async function checkIfFileWasNewlyCreated(file) { + const modifiedTime = fs.statSync(file).mtimeMs; + assert(Date.now() - modifiedTime < 500, file + ' was not modified'); + } + + async function testFileModification(sourceFilePath, resultFile) { + // run cdata.js to ensure html_*.h files are created + await execPromise('node tools/cdata.js'); + + // modify file + fs.appendFileSync(sourceFilePath, ' '); + // delay for 1 second to ensure the modified time is different + await new Promise(resolve => setTimeout(resolve, 1000)); + + // run script cdata.js again and wait for it to finish + await execPromise('node tools/cdata.js'); + + checkIfFileWasNewlyCreated(path.join(folderPath, resultFile)); + } + + describe('should build if', () => { + it('html_*.h files are missing', async () => { + await deleteBuiltFiles(); + await runAndCheckIfBuiltFilesExist(); + }); + + it('only one html_*.h file is missing', async () => { + // run script cdata.js and wait for it to finish + await execPromise('node tools/cdata.js'); + + // delete a random html_*.h file + let files = await fs.promises.readdir(folderPath); + let htmlFiles = files.filter(file => file.startsWith('html_') && path.extname(file) === '.h'); + const randomFile = htmlFiles[Math.floor(Math.random() * htmlFiles.length)]; + await fs.promises.unlink(path.join(folderPath, randomFile)); + + await runAndCheckIfBuiltFilesExist(); + }); + + it('script was executed with -f or --force', async () => { + await execPromise('node tools/cdata.js'); + await new Promise(resolve => setTimeout(resolve, 1000)); + await execPromise('node tools/cdata.js --force'); + await checkIfFileWasNewlyCreated(path.join(folderPath, 'html_ui.h')); + await new Promise(resolve => setTimeout(resolve, 1000)); + await execPromise('node tools/cdata.js -f'); + await checkIfFileWasNewlyCreated(path.join(folderPath, 'html_ui.h')); + }); + + it('a file changes', async () => { + await testFileModification(path.join(dataPath, 'index.htm'), 'html_ui.h'); + }); + + it('a inlined file changes', async () => { + await testFileModification(path.join(dataPath, 'index.js'), 'html_ui.h'); + }); + + it('a settings file changes', async () => { + await testFileModification(path.join(dataPath, 'settings_leds.htm'), 'html_ui.h'); + }); + + it('the favicon changes', async () => { + await testFileModification(path.join(dataPath, 'favicon.ico'), 'html_ui.h'); + }); + + it('cdata.js changes', async () => { + await testFileModification('tools/cdata.js', 'html_ui.h'); + }); + }); + + describe('should not build if', () => { + it('the files are already built', async () => { + await deleteBuiltFiles(); + + // run script cdata.js and wait for it to finish + let startTime = Date.now(); + await execPromise('node tools/cdata.js'); + const firstRunTime = Date.now() - startTime; + + // run script cdata.js and wait for it to finish + startTime = Date.now(); + await execPromise('node tools/cdata.js'); + const secondRunTime = Date.now() - startTime; + + // check if second run was faster than the first (must be at least 2x faster) + assert(secondRunTime < firstRunTime / 2, 'html_*.h files were rebuilt'); + }); + }); +}); \ No newline at end of file diff --git a/tools/cdata.js b/tools/cdata.js index 4b0d15d4f..ef7e06f41 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -16,28 +16,59 @@ */ const fs = require("fs"); -const path = require('path'); +const path = require("path"); const inliner = require("inliner"); const zlib = require("zlib"); const CleanCSS = require("clean-css"); -const MinifyHTML = require("html-minifier-terser").minify; +const minifyHtml = require("html-minifier-terser").minify; const packageJson = require("../package.json"); +// Export functions for testing +module.exports = { isFileNewerThan, isAnyFileInFolderNewerThan }; + const output = ["wled00/html_ui.h", "wled00/html_pixart.h", "wled00/html_cpal.h", "wled00/html_pxmagic.h", "wled00/html_settings.h", "wled00/html_other.h"] -/** - * +// \x1b[34m is blue, \x1b[36m is cyan, \x1b[0m is reset +const wledBanner = ` +\t\x1b[34m## ## ## ######## ######## +\t\x1b[34m## ## ## ## ## ## ## +\t\x1b[34m## ## ## ## ## ## ## +\t\x1b[34m## ## ## ## ###### ## ## +\t\x1b[34m## ## ## ## ## ## ## +\t\x1b[34m## ## ## ## ## ## ## +\t\x1b[34m ### ### ######## ######## ######## +\t\t\x1b[36mbuild script for web UI +\x1b[0m`; + +const singleHeader = `/* + * Binary array for the Web UI. + * gzip is used for smaller size and improved speeds. + * + * Please see https://kno.wled.ge/advanced/custom-features/#changing-web-ui + * to find out how to easily modify the web UI source! */ -function hexdump(buffer,isHex=false) { + +`; + +const multiHeader = `/* + * More web UI HTML source arrays. + * This file is auto generated, please don't make any changes manually. + * + * Instead, see https://kno.wled.ge/advanced/custom-features/#changing-web-ui + * to find out how to easily modify the web UI source! + */ +`; + +function hexdump(buffer, isHex = false) { let lines = []; - for (let i = 0; i < buffer.length; i +=(isHex?32:16)) { + for (let i = 0; i < buffer.length; i += (isHex ? 32 : 16)) { var block; let hexArray = []; if (isHex) { block = buffer.slice(i, i + 32) - for (let j = 0; j < block.length; j +=2 ) { - hexArray.push("0x" + block.slice(j,j+2)) + for (let j = 0; j < block.length; j += 2) { + hexArray.push("0x" + block.slice(j, j + 2)) } } else { block = buffer.slice(i, i + 16); // cut buffer into blocks of 16 @@ -54,183 +85,112 @@ function hexdump(buffer,isHex=false) { return lines.join(",\n"); } -function strReplace(str, search, replacement) { - return str.split(search).join(replacement); -} - function adoptVersionAndRepo(html) { let repoUrl = packageJson.repository ? packageJson.repository.url : undefined; if (repoUrl) { repoUrl = repoUrl.replace(/^git\+/, ""); repoUrl = repoUrl.replace(/\.git$/, ""); - // Replace we - html = strReplace(html, "https://github.com/atuline/WLED", repoUrl); - html = strReplace(html, "https://github.com/Aircoookie/WLED", repoUrl); + html = html.replaceAll("https://github.com/atuline/WLED", repoUrl); + html = html.replaceAll("https://github.com/Aircoookie/WLED", repoUrl); } let version = packageJson.version; if (version) { - html = strReplace(html, "##VERSION##", version); + html = html.replaceAll("##VERSION##", version); } return html; } -function filter(str, type) { - str = adoptVersionAndRepo(str); - if (type === undefined) { +async function minify(str, type = "plain") { + const options = { + collapseWhitespace: true, + collapseBooleanAttributes: true, + collapseInlineTagWhitespace: true, + minifyCSS: true, + minifyJS: true, + removeAttributeQuotes: true, + removeComments: true, + sortAttributes: true, + sortClassName: true, + }; + + if (type == "plain") { return str; } else if (type == "css-minify") { return new CleanCSS({}).minify(str).styles; } else if (type == "js-minify") { - return MinifyHTML('', { - collapseWhitespace: true, - minifyJS: true, - continueOnParseError: false, - removeComments: true, - }).replace(/<[\/]*script>/g,''); + return await minifyHtml('', options).replace(/<[\/]*script>/g, ''); } else if (type == "html-minify") { - return MinifyHTML(str, { - collapseWhitespace: true, - maxLineLength: 80, - minifyCSS: true, - minifyJS: true, - continueOnParseError: false, - removeComments: true, - }); - } else if (type == "html-minify-ui") { - return MinifyHTML(str, { - collapseWhitespace: true, - conservativeCollapse: true, - maxLineLength: 80, - minifyCSS: true, - minifyJS: true, - continueOnParseError: false, - removeComments: true, - }); - } else { - console.warn("Unknown filter: " + type); - return str; + return await minifyHtml(str, options); } + + throw new Error("Unknown filter: " + type); } -function writeHtmlGzipped(sourceFile, resultFile, page) { +async function writeHtmlGzipped(sourceFile, resultFile, page) { console.info("Reading " + sourceFile); - new inliner(sourceFile, function (error, html) { - console.info("Inlined " + html.length + " characters"); - html = filter(html, "html-minify-ui"); - console.info("Minified to " + html.length + " characters"); - - if (error) { - console.warn(error); - throw error; - } + new inliner(sourceFile, async function (error, html) { + if (error) throw error; html = adoptVersionAndRepo(html); - zlib.gzip(html, { level: zlib.constants.Z_BEST_COMPRESSION }, function (error, result) { - if (error) { - console.warn(error); - throw error; - } - - console.info("Compressed " + result.length + " bytes"); - const array = hexdump(result); - const src = `/* - * Binary array for the Web UI. - * gzip is used for smaller size and improved speeds. - * - * Please see https://kno.wled.ge/advanced/custom-features/#changing-web-ui - * to find out how to easily modify the web UI source! - */ - -// Autogenerated from ${sourceFile}, do not edit!! -const uint16_t PAGE_${page}_L = ${result.length}; -const uint8_t PAGE_${page}[] PROGMEM = { -${array} -}; -`; - console.info("Writing " + resultFile); - fs.writeFileSync(resultFile, src); - }); + const originalLength = html.length; + html = await minify(html, "html-minify"); + const result = zlib.gzipSync(html, { level: zlib.constants.Z_BEST_COMPRESSION }); + console.info("Minified and compressed " + sourceFile + " from " + originalLength + " to " + result.length + " bytes"); + const array = hexdump(result); + let src = singleHeader; + src += `const uint16_t PAGE_${page}_L = ${result.length};\n`; + src += `const uint8_t PAGE_${page}[] PROGMEM = {\n${array}\n};\n\n`; + console.info("Writing " + resultFile); + fs.writeFileSync(resultFile, src); }); } -function specToChunk(srcDir, s) { - if (s.method == "plaintext") { - const buf = fs.readFileSync(srcDir + "/" + s.file); - const str = buf.toString("utf-8"); - const chunk = ` -// Autogenerated from ${srcDir}/${s.file}, do not edit!! -const char ${s.name}[] PROGMEM = R"${s.prepend || ""}${filter(str, s.filter)}${ - s.append || "" - }"; +async function specToChunk(srcDir, s) { + const buf = fs.readFileSync(srcDir + "/" + s.file); + let chunk = `\n// Autogenerated from ${srcDir}/${s.file}, do not edit!!\n` -`; - return s.mangle ? s.mangle(chunk) : chunk; - } else if (s.method == "gzip") { - const buf = fs.readFileSync(srcDir + "/" + s.file); - var str = buf.toString('utf-8'); - if (s.mangle) str = s.mangle(str); - const zip = zlib.gzipSync(filter(str, s.filter), { level: zlib.constants.Z_BEST_COMPRESSION }); - const result = hexdump(zip.toString('hex'), true); - const chunk = ` -// Autogenerated from ${srcDir}/${s.file}, do not edit!! -const uint16_t ${s.name}_length = ${zip.length}; -const uint8_t ${s.name}[] PROGMEM = { -${result} -}; - -`; - return chunk; - } else if (s.method == "binary") { - const buf = fs.readFileSync(srcDir + "/" + s.file); - const result = hexdump(buf); - const chunk = ` -// Autogenerated from ${srcDir}/${s.file}, do not edit!! -const uint16_t ${s.name}_length = ${buf.length}; -const uint8_t ${s.name}[] PROGMEM = { -${result} -}; - -`; - return chunk; - } else { - console.warn("Unknown method: " + s.method); - return undefined; - } -} - -function writeChunks(srcDir, specs, resultFile) { - let src = `/* - * More web UI HTML source arrays. - * This file is auto generated, please don't make any changes manually. - * Instead, see https://kno.wled.ge/advanced/custom-features/#changing-web-ui - * to find out how to easily modify the web UI source! - */ -`; - specs.forEach((s) => { - const file = srcDir + "/" + s.file; - try { - console.info("Reading " + file + " as " + s.name); - src += specToChunk(srcDir, s); - } catch (e) { - console.warn( - "Failed " + s.name + " from " + file, - e.message.length > 60 ? e.message.substring(0, 60) : e.message - ); + if (s.method == "plaintext" || s.method == "gzip") { + let str = buf.toString("utf-8"); + str = adoptVersionAndRepo(str); + const originalLength = str.length; + if (s.method == "gzip") { + if (s.mangle) str = s.mangle(str); + const zip = zlib.gzipSync(await minify(str, s.filter), { level: zlib.constants.Z_BEST_COMPRESSION }); + console.info("Minified and compressed " + s.file + " from " + originalLength + " to " + zip.length + " bytes"); + const result = hexdump(zip); + chunk += `const uint16_t ${s.name}_length = ${zip.length};\n`; + chunk += `const uint8_t ${s.name}[] PROGMEM = {\n${result}\n};\n\n`; + return chunk; + } else { + const minified = await minify(str, s.filter); + console.info("Minified " + s.file + " from " + originalLength + " to " + minified.length + " bytes"); + chunk += `const char ${s.name}[] PROGMEM = R"${s.prepend || ""}${minified}${s.append || ""}";\n\n`; + return s.mangle ? s.mangle(chunk) : chunk; } - }); + } else if (s.method == "binary") { + const result = hexdump(buf); + chunk += `const uint16_t ${s.name}_length = ${buf.length};\n`; + chunk += `const uint8_t ${s.name}[] PROGMEM = {\n${result}\n};\n\n`; + return chunk; + } + + throw new Error("Unknown method: " + s.method); +} + +async function writeChunks(srcDir, specs, resultFile) { + let src = multiHeader; + for (const s of specs) { + console.info("Reading " + srcDir + "/" + s.file + " as " + s.name); + src += await specToChunk(srcDir, s); + } console.info("Writing " + src.length + " characters into " + resultFile); fs.writeFileSync(resultFile, src); } // Check if a file is newer than a given time function isFileNewerThan(filePath, time) { - try { - const stats = fs.statSync(filePath); - return stats.mtimeMs > time; - } catch (e) { - console.error(`Failed to get stats for file ${filePath}:`, e); - return false; - } + const stats = fs.statSync(filePath); + return stats.mtimeMs > time; } // Check if any file in a folder (or its subfolders) is newer than a given time @@ -248,21 +208,30 @@ function isAnyFileInFolderNewerThan(folderPath, time) { return false; } +// Check if the web UI is already built function isAlreadyBuilt(folderPath) { let lastBuildTime = Infinity; for (const file of output) { try { lastBuildTime = Math.min(lastBuildTime, fs.statSync(file).mtimeMs); - } - catch (e) { + } catch (e) { + if (e.code !== 'ENOENT') throw e; + console.info("File " + file + " does not exist. Rebuilding..."); return false; } } - return !isAnyFileInFolderNewerThan(folderPath, lastBuildTime); + return !isAnyFileInFolderNewerThan(folderPath, lastBuildTime) && !isFileNewerThan("tools/cdata.js", lastBuildTime); } +// Don't run this script if we're in a test environment +if (process.env.NODE_ENV === 'test') { + return; +} + +console.info(wledBanner); + if (isAlreadyBuilt("wled00/data") && process.argv[2] !== '--force' && process.argv[2] !== '-f') { console.info("Web UI is already built"); return; @@ -283,7 +252,7 @@ writeChunks( filter: "css-minify", mangle: (str) => str - .replace("%%","%") + .replace("%%", "%") }, { file: "settings.htm", diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.h index b11a22a83..55803a24d 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.h @@ -445,7 +445,7 @@ void BobLightUsermod::pollBob() { //strip.setPixelColor(light_id, RGBW32(red, green, blue, 0)); setRealtimePixel(light_id, red, green, blue, 0); } // currently no support for interpolation or speed, we just ignore this - } else if (input.startsWith(F("sync"))) { + } else if (input.startsWith("sync")) { BobSync(); } else { // Client sent gibberish diff --git a/usermods/wireguard/wireguard.h b/usermods/wireguard/wireguard.h index a83b9fe78..c4e1fd504 100644 --- a/usermods/wireguard/wireguard.h +++ b/usermods/wireguard/wireguard.h @@ -67,8 +67,8 @@ class WireguardUsermod : public Usermod { JsonObject top = root.createNestedObject(F("WireGuard")); top[F("host")] = endpoint_address; top[F("port")] = endpoint_port; - top[F("ip")] = local_ip.toString(); - top[F("psk")] = preshared_key; + top["ip"] = local_ip.toString(); + top["psk"] = preshared_key; top[F("pem")] = private_key; top[F("pub")] = public_key; top[F("tz")] = posix_tz; @@ -77,11 +77,11 @@ class WireguardUsermod : public Usermod { bool readFromConfig(JsonObject& root) { JsonObject top = root[F("WireGuard")]; - if (top["host"].isNull() || top["port"].isNull() || top["ip"].isNull() || top["pem"].isNull() || top["pub"].isNull() || top["tz"].isNull()) { + if (top[F("host")].isNull() || top[F("port")].isNull() || top["ip"].isNull() || top[F("pem")].isNull() || top[F("pub")].isNull() || top[F("tz")].isNull()) { is_enabled = false; return false; } else { - const char* host = top["host"]; + const char* host = top[F("host")]; strncpy(endpoint_address, host, 100); const char* ip_s = top["ip"]; @@ -89,16 +89,16 @@ class WireguardUsermod : public Usermod { sscanf(ip_s, "%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]); local_ip = IPAddress(ip[0], ip[1], ip[2], ip[3]); - const char* pem = top["pem"]; + const char* pem = top[F("pem")]; strncpy(private_key, pem, 45); - const char* pub = top["pub"]; + const char* pub = top[F("pub")]; strncpy(public_key, pub, 45); - const char* tz = top["tz"]; + const char* tz = top[F("tz")]; strncpy(posix_tz, tz, 150); - endpoint_port = top["port"]; + endpoint_port = top[F("port")]; if (!top["psk"].isNull()) { const char* psk = top["psk"]; diff --git a/usermods/word-clock-matrix/usermod_word_clock_matrix.h b/usermods/word-clock-matrix/usermod_word_clock_matrix.h index 582563004..506c1275e 100644 --- a/usermods/word-clock-matrix/usermod_word_clock_matrix.h +++ b/usermods/word-clock-matrix/usermod_word_clock_matrix.h @@ -325,8 +325,8 @@ public: void addToConfig(JsonObject& root) { JsonObject modName = root.createNestedObject("id"); - modName["mdns"] = "wled-word-clock"; - modName["name"] = "WLED WORD CLOCK"; + modName[F("mdns")] = "wled-word-clock"; + modName[F("name")] = "WLED WORD CLOCK"; } uint16_t getId() diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a27fc4fbe..a6303810f 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1848,10 +1848,10 @@ uint16_t mode_lightning(void) { } SEGENV.aux1--; - SEGENV.step = millis(); + SEGENV.step = strip.now; //return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds } else { - if (millis() - SEGENV.step > SEGENV.aux0) { + if (strip.now - SEGENV.step > SEGENV.aux0) { SEGENV.aux1--; if (SEGENV.aux1 < 2) SEGENV.aux1 = 0; @@ -1859,7 +1859,7 @@ uint16_t mode_lightning(void) { if (SEGENV.aux1 == 2) { SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes } - SEGENV.step = millis(); + SEGENV.step = strip.now; } } return FRAMETIME; @@ -1929,22 +1929,102 @@ static const char _data_FX_MODE_JUGGLE[] PROGMEM = "Juggle@!,Trail;;!;;sx=64,ix= uint16_t mode_palette() { - uint16_t counter = 0; - if (SEGMENT.speed != 0) - { - counter = (strip.now * ((SEGMENT.speed >> 3) +1)) & 0xFFFF; - counter = counter >> 8; - } + // Set up some compile time constants so that we can handle integer and float based modes using the same code base. +#ifdef ESP8266 + using mathType = int32_t; + using wideMathType = int64_t; + using angleType = uint16_t; + constexpr mathType sInt16Scale = 0x7FFF; + constexpr mathType maxAngle = 0x8000; + constexpr mathType staticRotationScale = 256; + constexpr mathType animatedRotationScale = 1; + constexpr int16_t (*sinFunction)(uint16_t) = &sin16; + constexpr int16_t (*cosFunction)(uint16_t) = &cos16; +#else + using mathType = float; + using wideMathType = float; + using angleType = float; + constexpr mathType sInt16Scale = 1.0f; + constexpr mathType maxAngle = M_PI / 256.0; + constexpr mathType staticRotationScale = 1.0f; + constexpr mathType animatedRotationScale = M_TWOPI / double(0xFFFF); + constexpr float (*sinFunction)(float) = &sin_t; + constexpr float (*cosFunction)(float) = &cos_t; +#endif + const bool isMatrix = strip.isMatrix; + const int cols = SEGMENT.virtualWidth(); + const int rows = isMatrix ? SEGMENT.virtualHeight() : strip.getActiveSegmentsNum(); - for (int i = 0; i < SEGLEN; i++) - { - uint8_t colorIndex = (i * 255 / SEGLEN) - counter; - SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, PALETTE_MOVING_WRAP, 255)); - } + const int inputShift = SEGMENT.speed; + const int inputSize = SEGMENT.intensity; + const int inputRotation = SEGMENT.custom1; + const bool inputAnimateShift = SEGMENT.check1; + const bool inputAnimateRotation = SEGMENT.check2; + const bool inputAssumeSquare = SEGMENT.check3; + const angleType theta = (!inputAnimateRotation) ? (inputRotation * maxAngle / staticRotationScale) : (((strip.now * ((inputRotation >> 4) +1)) & 0xFFFF) * animatedRotationScale); + const mathType sinTheta = sinFunction(theta); + const mathType cosTheta = cosFunction(theta); + + const mathType maxX = std::max(1, cols-1); + const mathType maxY = std::max(1, rows-1); + // Set up some parameters according to inputAssumeSquare, so that we can handle anamorphic mode using the same code base. + const mathType maxXIn = inputAssumeSquare ? maxX : mathType(1); + const mathType maxYIn = inputAssumeSquare ? maxY : mathType(1); + const mathType maxXOut = !inputAssumeSquare ? maxX : mathType(1); + const mathType maxYOut = !inputAssumeSquare ? maxY : mathType(1); + const mathType centerX = sInt16Scale * maxXOut / mathType(2); + const mathType centerY = sInt16Scale * maxYOut / mathType(2); + // The basic idea for this effect is to rotate a rectangle that is filled with the palette along one axis, then map our + // display to it, to find what color a pixel should have. + // However, we want a) no areas of solid color (in front of or behind the palette), and b) we want to make use of the full palette. + // So the rectangle needs to have exactly the right size. That size depends on the rotation. + // This scale computation here only considers one dimension. You can think of it like the rectangle is always scaled so that + // the left and right most points always match the left and right side of the display. + const mathType scale = std::abs(sinTheta) + (std::abs(cosTheta) * maxYOut / maxXOut); + // 2D simulation: + // If we are dealing with a 1D setup, we assume that each segment represents one line on a 2-dimensional display. + // The function is called once per segments, so we need to handle one line at a time. + const int yFrom = isMatrix ? 0 : strip.getCurrSegmentId(); + const int yTo = isMatrix ? maxY : yFrom; + for (int y = yFrom; y <= yTo; ++y) { + // translate, scale, rotate + const mathType ytCosTheta = mathType((wideMathType(cosTheta) * wideMathType(y * sInt16Scale - centerY * maxYIn))/wideMathType(maxYIn * scale)); + for (int x = 0; x < cols; ++x) { + // translate, scale, rotate + const mathType xtSinTheta = mathType((wideMathType(sinTheta) * wideMathType(x * sInt16Scale - centerX * maxXIn))/wideMathType(maxXIn * scale)); + // Map the pixel coordinate to an imaginary-rectangle-coordinate. + // The y coordinate doesn't actually matter, as our imaginary rectangle is filled with the palette from left to right, + // so all points at a given x-coordinate have the same color. + const mathType sourceX = xtSinTheta + ytCosTheta + centerX; + // The computation was scaled just right so that the result should always be in range [0, maxXOut], but enforce this anyway + // to account for imprecision. Then scale it so that the range is [0, 255], which we can use with the palette. + int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * 255) / (sInt16Scale * maxXOut); + // inputSize determines by how much we want to scale the palette: + // values < 128 display a fraction of a palette, + // values > 128 display multiple palettes. + if (inputSize <= 128) { + colorIndex = (colorIndex * inputSize) / 128; + } else { + // Linear function that maps colorIndex 128=>1, 256=>9. + // With this function every full palette repetition is exactly 16 configuration steps wide. + // That allows displaying exactly 2 repetitions for example. + colorIndex = ((inputSize - 112) * colorIndex) / 16; + } + // Finally, shift the palette a bit. + const int paletteOffset = (!inputAnimateShift) ? (inputShift-128) : (((strip.now * ((inputShift >> 3) +1)) & 0xFFFF) >> 8); + colorIndex += paletteOffset; + const uint32_t color = SEGMENT.color_wheel((uint8_t)colorIndex); + if (isMatrix) { + SEGMENT.setPixelColorXY(x, y, color); + } else { + SEGMENT.setPixelColor(x, color); + } + } + } return FRAMETIME; } -static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Cycle speed;;!;;c3=0,o2=0"; +static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation,,,Animate Shift,Animate Rotation,Anamorphic;;!;12;c1=128,c2=128,c3=128,o1=1,o2=1,o3=0"; // WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active @@ -2899,7 +2979,7 @@ uint16_t mode_bouncing_balls(void) { uint16_t numBalls = (SEGMENT.intensity * (maxNumBalls - 1)) / 255 + 1; // minimum 1 ball const float gravity = -9.81f; // standard value of gravity const bool hasCol2 = SEGCOLOR(2); - const unsigned long time = millis(); + const unsigned long time = strip.now; if (SEGENV.call == 0) { for (size_t i = 0; i < maxNumBalls; i++) balls[i].lastBounceTime = time; @@ -3336,7 +3416,7 @@ uint16_t mode_starburst(void) { if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - uint32_t it = millis(); + uint32_t it = strip.now; star* stars = reinterpret_cast(SEGENV.data); @@ -3692,7 +3772,7 @@ uint16_t mode_tetrix(void) { // initialize dropping on first call or segment full if (SEGENV.call == 0) { drop->stack = 0; // reset brick stack size - drop->step = millis() + 2000; // start by fading out strip + drop->step = strip.now + 2000; // start by fading out strip if (SEGMENT.check1) drop->col = 0;// use only one color from palette } @@ -3726,13 +3806,13 @@ uint16_t mode_tetrix(void) { } else { // we hit bottom drop->step = 0; // proceed with next brick, go back to init drop->stack += drop->brick; // increase the stack size - if (drop->stack >= SEGLEN) drop->step = millis() + 2000; // fade out stack + if (drop->stack >= SEGLEN) drop->step = strip.now + 2000; // fade out stack } } if (drop->step > 2) { // fade strip drop->brick = 0; // reset brick size (no more growing) - if (drop->step > millis()) { + if (drop->step > strip.now) { // allow fading of virtual strip for (int i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend } else { @@ -3991,7 +4071,7 @@ uint16_t mode_sunrise() { //speed 60 - 120 : sunset time in minutes - 60; //speed above: "breathing" rise and set if (SEGENV.call == 0 || SEGMENT.speed != SEGENV.aux0) { - SEGENV.step = millis(); //save starting time, millis() because now can change from sync + SEGENV.step = millis(); //save starting time, millis() because strip.now can change from sync SEGENV.aux0 = SEGMENT.speed; } @@ -4104,9 +4184,9 @@ uint16_t mode_noisepal(void) { // Slow noise CRGBPalette16* palettes = reinterpret_cast(SEGENV.data); uint16_t changePaletteMs = 4000 + SEGMENT.speed *10; //between 4 - 6.5sec - if (millis() - SEGENV.step > changePaletteMs) + if (strip.now - SEGENV.step > changePaletteMs) { - SEGENV.step = millis(); + SEGENV.step = strip.now; uint8_t baseI = random8(); palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255))); @@ -4261,7 +4341,7 @@ uint16_t mode_dancing_shadows(void) SEGMENT.fill(BLACK); - unsigned long time = millis(); + unsigned long time = strip.now; bool respawn = false; for (size_t i = 0; i < numSpotlights; i++) { @@ -4455,8 +4535,8 @@ uint16_t mode_tv_simulator(void) { } // create a new sceene - if (((millis() - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { - tvSimulator->sceeneStart = millis(); // remember the start of the new sceene + if (((strip.now - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { + tvSimulator->sceeneStart = strip.now; // remember the start of the new sceene tvSimulator->sceeneDuration = random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider) tvSimulator->sceeneColorHue = random16( 0, 768); // random start color-tone for the sceene tvSimulator->sceeneColorSat = random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene @@ -4507,11 +4587,11 @@ uint16_t mode_tv_simulator(void) { tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time if (random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time - tvSimulator->startTime = millis(); + tvSimulator->startTime = strip.now; } // end of initialization // how much time is elapsed ? - tvSimulator->elapsed = millis() - tvSimulator->startTime; + tvSimulator->elapsed = strip.now - tvSimulator->startTime; // fade from prev volor to next color if (tvSimulator->elapsed < tvSimulator->fadeTime) { @@ -4715,7 +4795,7 @@ uint16_t mode_perlinmove(void) { if (SEGLEN == 1) return mode_static(); SEGMENT.fade_out(255-SEGMENT.custom1); for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) { - uint16_t locn = inoise16(millis()*128/(260-SEGMENT.speed)+i*15000, millis()*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. + uint16_t locn = inoise16(strip.now*128/(260-SEGMENT.speed)+i*15000, strip.now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. uint16_t pixloc = map(locn, 50*256, 192*256, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over. SEGMENT.setPixelColor(pixloc, SEGMENT.color_from_palette(pixloc%255, false, PALETTE_SOLID_WRAP, 0)); } @@ -4732,7 +4812,7 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel uint16_t mode_wavesins(void) { for (int i = 0; i < SEGLEN; i++) { - uint8_t bri = sin8(millis()/4 + i * SEGMENT.intensity); + uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, bri)); @@ -4750,8 +4830,8 @@ static const char _data_FX_MODE_WAVESINS[] PROGMEM = "Wavesins@!,Brightness vari uint16_t mode_FlowStripe(void) { const uint16_t hl = SEGLEN * 10 / 13; - uint8_t hue = millis() / (SEGMENT.speed+1); - uint32_t t = millis() / (SEGMENT.intensity/8+1); + uint8_t hue = strip.now / (SEGMENT.speed+1); + uint32_t t = strip.now / (SEGMENT.intensity/8+1); for (int i = 0; i < SEGLEN; i++) { int c = (abs(i - hl) / hl) * 127; @@ -4781,7 +4861,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma uint16_t x, y; SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails - unsigned long t = millis()/128; // timebase + unsigned long t = strip.now/128; // timebase // outer stars for (size_t i = 0; i < 8; i++) { x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); @@ -4867,8 +4947,8 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa SEGMENT.fadeToBlackBy(64); for (int i = 0; i < cols; i++) { - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+millis()/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+millis()/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); } SEGMENT.blur(SEGMENT.intensity>>3); @@ -4880,7 +4960,7 @@ static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur;;!;2"; ///////////////////////// // 2D DNA Spiral // ///////////////////////// -uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulmatelights.com/gallery/810 , modified by: Andrew Tuline +uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulmatelights.com/gallery/512-dna-spiral-variation , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up const uint16_t cols = SEGMENT.virtualWidth(); @@ -4890,10 +4970,10 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma SEGMENT.fill(BLACK); } - uint8_t speeds = SEGMENT.speed/2 + 1; + uint8_t speeds = SEGMENT.speed/2 + 7; uint8_t freq = SEGMENT.intensity/8; - uint32_t ms = millis() / 20; + uint32_t ms = strip.now / 20; SEGMENT.fadeToBlackBy(135); for (int i = 0; i < rows; i++) { @@ -4933,7 +5013,7 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli SEGMENT.fadeToBlackBy(128); const uint16_t maxDim = MAX(cols, rows)/2; - unsigned long t = millis() / (32 - (SEGMENT.speed>>3)); + unsigned long t = strip.now / (32 - (SEGMENT.speed>>3)); unsigned long t_20 = t/20; // softhack007: pre-calculating this gives about 10% speedup for (float i = 1; i < maxDim; i += 0.25) { float angle = radians(t * (maxDim - i)); @@ -4972,7 +5052,7 @@ uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline for (int j=0; j < cols; j++) { for (int i=0; i < rows; i++) { - indexx = inoise8(j*yscale*rows/255, i*xscale+millis()/4); // We're moving along our Perlin map. + indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4); // We're moving along our Perlin map. SEGMENT.setPixelColorXY(j, i, ColorFromPalette(SEGPALETTE, min(i*(indexx)>>4, 255), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. } // for i } // for j @@ -5203,8 +5283,8 @@ uint16_t mode_2DJulia(void) { // An animated Julia set reAl = -0.94299f; // PixelBlaze example imAg = 0.3162f; - reAl += sin_t((float)millis()/305.f)/20.f; - imAg += sin_t((float)millis()/405.f)/20.f; + reAl += sin_t((float)strip.now/305.f)/20.f; + imAg += sin_t((float)strip.now/405.f)/20.f; dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. dy = (ymax - ymin) / (rows); @@ -5263,7 +5343,7 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline const uint16_t rows = SEGMENT.virtualHeight(); SEGMENT.fadeToBlackBy(SEGMENT.intensity); - uint_fast16_t phase = (millis() * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed + uint_fast16_t phase = (strip.now * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed //for (int i=0; i < 4*(cols+rows); i ++) { for (int i=0; i < 256; i ++) { @@ -5273,7 +5353,7 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline uint_fast8_t ylocn = cos8(phase/2 + i*2); xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map() - SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(millis()/100+i, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); } return FRAMETIME; @@ -5423,7 +5503,7 @@ uint16_t mode_2Dnoise(void) { // By Andrew Tuline for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { - uint8_t pixelHue8 = inoise8(x * scale, y * scale, millis() / (16 - SEGMENT.speed/16)); + uint8_t pixelHue8 = inoise8(x * scale, y * scale, strip.now / (16 - SEGMENT.speed/16)); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, pixelHue8)); } } @@ -5443,7 +5523,7 @@ uint16_t mode_2DPlasmaball(void) { // By: Stepko https://edito const uint16_t rows = SEGMENT.virtualHeight(); SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2); - uint_fast32_t t = (millis() * 8) / (256 - SEGMENT.speed); // optimized to avoid float + uint_fast32_t t = (strip.now * 8) / (256 - SEGMENT.speed); // optimized to avoid float for (int i = 0; i < cols; i++) { uint16_t thisVal = inoise8(i * 30, t, t); uint16_t thisMax = map(thisVal, 0, 255, 0, cols-1); @@ -5561,7 +5641,7 @@ uint16_t mode_2DSindots(void) { // By: ldirko http SEGMENT.fadeToBlackBy(SEGMENT.custom1>>3); - byte t1 = millis() / (257 - SEGMENT.speed); // 20; + byte t1 = strip.now / (257 - SEGMENT.speed); // 20; byte t2 = sin8(t1) / 4 * 2; for (int i = 0; i < 13; i++) { byte x = sin8(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! @@ -5600,11 +5680,9 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g uint8_t n = beatsin8(15, kBorderWidth, rows-kBorderWidth); uint8_t p = beatsin8(20, kBorderWidth, rows-kBorderWidth); - uint16_t ms = millis(); - - SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, ms/29, 255, LINEARBLEND)); - SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, ms/41, 255, LINEARBLEND)); - SEGMENT.addPixelColorXY(k, p, ColorFromPalette(SEGPALETTE, ms/73, 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, strip.now/29, 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, strip.now/41, 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(k, p, ColorFromPalette(SEGPALETTE, strip.now/73, 255, LINEARBLEND)); return FRAMETIME; } // mode_2Dsquaredswirl() @@ -5627,7 +5705,7 @@ uint16_t mode_2DSunradiation(void) { // By: ldirko https://edi SEGMENT.fill(BLACK); } - unsigned long t = millis() / 4; + unsigned long t = strip.now / 4; int index = 0; uint8_t someVal = SEGMENT.speed/4; // Was 25. for (int j = 0; j < (rows + 2); j++) { @@ -5759,14 +5837,14 @@ uint16_t mode_2Dcrazybees(void) { int8_t deltaX, deltaY, signX, signY, error; void aimed(uint16_t w, uint16_t h) { //random16_set_seed(millis()); - aimX = random8(0, w); - aimY = random8(0, h); - hue = random8(); + aimX = random8(0, w); + aimY = random8(0, h); + hue = random8(); deltaX = abs(aimX - posX); deltaY = abs(aimY - posY); - signX = posX < aimX ? 1 : -1; - signY = posY < aimY ? 1 : -1; - error = deltaX - deltaY; + signX = posX < aimX ? 1 : -1; + signY = posY < aimY ? 1 : -1; + error = deltaX - deltaY; }; } bee_t; @@ -5774,6 +5852,7 @@ uint16_t mode_2Dcrazybees(void) { bee_t *bee = reinterpret_cast(SEGENV.data); if (SEGENV.call == 0) { + random16_set_seed(strip.now); for (size_t i = 0; i < n; i++) { bee[i].posX = random8(0, cols); bee[i].posY = random8(0, rows); @@ -5781,8 +5860,8 @@ uint16_t mode_2Dcrazybees(void) { } } - if (millis() > SEGENV.step) { - SEGENV.step = millis() + (FRAMETIME * 16 / ((SEGMENT.speed>>4)+1)); + if (strip.now > SEGENV.step) { + SEGENV.step = strip.now + (FRAMETIME * 16 / ((SEGMENT.speed>>4)+1)); SEGMENT.fadeToBlackBy(32); @@ -5859,8 +5938,8 @@ uint16_t mode_2Dghostrider(void) { } } - if (millis() > SEGENV.step) { - SEGENV.step = millis() + 1024 / (cols+rows); + if (strip.now > SEGENV.step) { + SEGENV.step = strip.now + 1024 / (cols+rows); SEGMENT.fadeToBlackBy((SEGMENT.speed>>2)+64); @@ -5948,7 +6027,7 @@ uint16_t mode_2Dfloatingblobs(void) { // Bounce balls around for (size_t i = 0; i < Amount; i++) { - if (SEGENV.step < millis()) blob->color[i] = add8(blob->color[i], 4); // slowly change color + if (SEGENV.step < strip.now) blob->color[i] = add8(blob->color[i], 4); // slowly change color // change radius if needed if (blob->grow[i]) { // enlarge radius until it is >= 4 @@ -5995,7 +6074,7 @@ uint16_t mode_2Dfloatingblobs(void) { } SEGMENT.blur(SEGMENT.custom1>>2); - if (SEGENV.step < millis()) SEGENV.step = millis() + 2000; // change colors every 2 seconds + if (SEGENV.step < strip.now) SEGENV.step = strip.now + 2000; // change colors every 2 seconds return FRAMETIME; } @@ -6059,13 +6138,12 @@ uint16_t mode_2Dscrollingtext(void) { } const int numberOfLetters = strlen(text); - const unsigned long now = millis(); // reduce millis() calls int width = (numberOfLetters * rotLW); int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-rotLH)/2; if (width <= cols) { // scroll vertically (e.g. ^^ Way out ^^) if it fits int speed = map(SEGMENT.speed, 0, 255, 5000, 1000); - int frac = now % speed + 1; + int frac = strip.now % speed + 1; if (SEGMENT.intensity == 255) { yoffset = (2 * frac * rows)/speed - rows; } else if (SEGMENT.intensity == 0) { @@ -6073,7 +6151,7 @@ uint16_t mode_2Dscrollingtext(void) { } } - if (SEGENV.step < now) { + if (SEGENV.step < strip.now) { // calculate start offset if (width > cols) { if (SEGMENT.check3) { @@ -6082,7 +6160,7 @@ uint16_t mode_2Dscrollingtext(void) { } else ++SEGENV.aux0 %= width + cols; } else SEGENV.aux0 = (cols + width)/2; ++SEGENV.aux1 &= 0xFF; // color shift - SEGENV.step = now + map(SEGMENT.speed, 0, 255, 250, 50); // shift letters every ~250ms to ~50ms + SEGENV.step = strip.now + map(SEGMENT.speed, 0, 255, 250, 50); // shift letters every ~250ms to ~50ms } if (!SEGMENT.check2) SEGMENT.fade_out(255 - (SEGMENT.custom1>>4)); // trail @@ -6130,6 +6208,51 @@ uint16_t mode_2Ddriftrose(void) { } static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;;2"; +///////////////////////////// +// 2D PLASMA ROTOZOOMER // +///////////////////////////// +// Plasma Rotozoomer by ldirko (c)2020 [https://editor.soulmatelights.com/gallery/457-plasma-rotozoomer], adapted for WLED by Blaz Kristan (AKA blazoncek) +uint16_t mode_2Dplasmarotozoom() { + if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up + + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); + + uint16_t dataSize = SEGMENT.length() + sizeof(float); + if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + float *a = reinterpret_cast(SEGENV.data); + byte *plasma = reinterpret_cast(SEGENV.data+sizeof(float)); + + uint16_t ms = strip.now/15; + + // plasma + for (int j = 0; j < rows; j++) { + int index = j*cols; + for (int i = 0; i < cols; i++) { + if (SEGMENT.check1) plasma[index+i] = (i * 4 ^ j * 4) + ms / 6; + else plasma[index+i] = inoise8(i * 40, j * 40, ms); + } + } + + // rotozoom + float f = (sin_t(*a/2)+((128-SEGMENT.intensity)/128.0f)+1.1f)/1.5f; // scale factor + float kosinus = cos_t(*a) * f; + float sinus = sin_t(*a) * f; + for (int i = 0; i < cols; i++) { + float u1 = i * kosinus; + float v1 = i * sinus; + for (int j = 0; j < rows; j++) { + byte u = abs8(u1 - j * sinus) % cols; + byte v = abs8(v1 + j * kosinus) % rows; + SEGMENT.setPixelColorXY(i, j, SEGMENT.color_from_palette(plasma[v*cols+u], false, PALETTE_SOLID_WRAP, 0)); + } + } + *a -= 0.03f + float(SEGENV.speed-128)*0.0002f; // rotation speed + + return FRAMETIME; +} +static const char _data_FX_MODE_2DPLASMAROTOZOOM[] PROGMEM = "Rotozoomer@!,Scale,,,,Alt;;!;2;pal=54"; + #endif // WLED_DISABLE_2D @@ -6280,7 +6403,6 @@ uint16_t mode_2DSwirl(void) { uint8_t j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); uint8_t ni = (cols - 1) - i; uint8_t nj = (cols - 1) - j; - uint16_t ms = millis(); um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -6290,12 +6412,12 @@ uint16_t mode_2DSwirl(void) { float volumeSmth = *(float*) um_data->u_data[0]; //ewowi: use instead of sampleAvg??? int16_t volumeRaw = *(int16_t*) um_data->u_data[1]; - SEGMENT.addPixelColorXY( i, j, ColorFromPalette(SEGPALETTE, (ms / 11 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 11, 200, 255); - SEGMENT.addPixelColorXY( j, i, ColorFromPalette(SEGPALETTE, (ms / 13 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 13, 200, 255); - SEGMENT.addPixelColorXY(ni,nj, ColorFromPalette(SEGPALETTE, (ms / 17 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 17, 200, 255); - SEGMENT.addPixelColorXY(nj,ni, ColorFromPalette(SEGPALETTE, (ms / 29 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 29, 200, 255); - SEGMENT.addPixelColorXY( i,nj, ColorFromPalette(SEGPALETTE, (ms / 37 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 37, 200, 255); - SEGMENT.addPixelColorXY(ni, j, ColorFromPalette(SEGPALETTE, (ms / 41 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 41, 200, 255); + SEGMENT.addPixelColorXY( i, j, ColorFromPalette(SEGPALETTE, (strip.now / 11 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 11, 200, 255); + SEGMENT.addPixelColorXY( j, i, ColorFromPalette(SEGPALETTE, (strip.now / 13 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 13, 200, 255); + SEGMENT.addPixelColorXY(ni,nj, ColorFromPalette(SEGPALETTE, (strip.now / 17 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 17, 200, 255); + SEGMENT.addPixelColorXY(nj,ni, ColorFromPalette(SEGPALETTE, (strip.now / 29 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 29, 200, 255); + SEGMENT.addPixelColorXY( i,nj, ColorFromPalette(SEGPALETTE, (strip.now / 37 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 37, 200, 255); + SEGMENT.addPixelColorXY(ni, j, ColorFromPalette(SEGPALETTE, (strip.now / 41 + volumeSmth*4), volumeRaw * SEGMENT.intensity / 64, LINEARBLEND)); //CHSV( ms / 41, 200, 255); return FRAMETIME; } // mode_2DSwirl() @@ -6321,7 +6443,7 @@ uint16_t mode_2DWaverly(void) { SEGMENT.fadeToBlackBy(SEGMENT.speed); - long t = millis() / 2; + long t = strip.now / 2; for (int i = 0; i < cols; i++) { uint16_t thisVal = (1 + SEGMENT.intensity/64) * inoise8(i * 45 , t , t)/2; // use audio if available @@ -6383,7 +6505,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. uint8_t gravity = 8 - SEGMENT.speed/32; for (int i=0; itopLED--; if (gravcen->topLED >= 0) { - SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); - SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); } gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; @@ -6435,7 +6557,7 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew uint8_t gravity = 8 - SEGMENT.speed/32; for (int i=0; itopLED--; if (gravcen->topLED > 0) { - SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(millis(), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); } gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; @@ -6519,7 +6641,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. uint16_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); for (size_t i=0; i SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left for (int i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right } @@ -6775,7 +6897,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. } for (int i=0; iu_data[0]; - myVals[millis()%32] = volumeSmth; // filling values semi randomly + myVals[strip.now%32] = volumeSmth; // filling values semi randomly SEGMENT.fade_out(64+(SEGMENT.speed>>1)); @@ -7188,7 +7310,7 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli uint8_t numBins = map(SEGMENT.intensity,0,255,0,16); // Map slider to fftResult bins. for (int i=0; i= (256U - SEGMENT.intensity)) { - SEGENV.step = millis(); + if (strip.now - SEGENV.step >= (256U - SEGMENT.intensity)) { + SEGENV.step = strip.now; rippleTime = true; } @@ -7522,7 +7644,7 @@ uint16_t mode_2Ddistortionwaves() { uint8_t w = 2; - uint16_t a = millis()/32; + uint16_t a = strip.now/32; uint16_t a2 = a/2; uint16_t a3 = a/3; @@ -7740,7 +7862,7 @@ uint16_t mode_2Dwavingcell() { const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); - uint32_t t = millis()/(257-SEGMENT.speed); + uint32_t t = strip.now/(257-SEGMENT.speed); uint8_t aX = SEGMENT.custom1/16 + 9; uint8_t aY = SEGMENT.custom2/16 + 1; uint8_t aZ = SEGMENT.custom3 + 1; @@ -7945,6 +8067,7 @@ void WS2812FX::setupEffectData() { // --- 2D effects --- #ifndef WLED_DISABLE_2D + addEffect(FX_MODE_2DPLASMAROTOZOOM, &mode_2Dplasmarotozoom, _data_FX_MODE_2DPLASMAROTOZOOM); addEffect(FX_MODE_2DSPACESHIPS, &mode_2Dspaceships, _data_FX_MODE_2DSPACESHIPS); addEffect(FX_MODE_2DCRAZYBEES, &mode_2Dcrazybees, _data_FX_MODE_2DCRAZYBEES); addEffect(FX_MODE_2DGHOSTRIDER, &mode_2Dghostrider, _data_FX_MODE_2DGHOSTRIDER); diff --git a/wled00/FX.h b/wled00/FX.h index c4725ec97..abf33f997 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -241,7 +241,7 @@ #define FX_MODE_CHUNCHUN 111 #define FX_MODE_DANCING_SHADOWS 112 #define FX_MODE_WASHING_MACHINE 113 -// #define FX_MODE_CANDY_CANE 114 // removed in 0.14! +#define FX_MODE_2DPLASMAROTOZOOM 114 // was Candy Cane prior to 0.14 (use Chase 2) #define FX_MODE_BLENDS 115 #define FX_MODE_TV_SIMULATOR 116 #define FX_MODE_DYNAMIC_SMOOTH 117 // candidate for removal (check3 in dynamic) @@ -802,8 +802,7 @@ class WS2812FX { // 96 bytes getActiveSegmentsNum(void), getFirstSelectedSegId(void), getLastActiveSegmentId(void), - getActiveSegsLightCapabilities(bool selectedOnly = false), - setPixelSegment(uint8_t n); + getActiveSegsLightCapabilities(bool selectedOnly = false); inline uint8_t getBrightness(void) { return _brightness; } // returns current strip brightness inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 4f334779d..eeaa2c1e1 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -440,6 +440,7 @@ uint8_t IRAM_ATTR Segment::currentMode() { } uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { + if (slot >= NUM_COLORS) slot = 0; #ifndef WLED_DISABLE_MODE_BLEND return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot]; #else @@ -1025,7 +1026,7 @@ void Segment::blur(uint8_t blur_amount) { * Inspired by the Adafruit examples. */ uint32_t Segment::color_wheel(uint8_t pos) { - if (palette) return color_from_palette(pos, false, true, 0); + if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true" uint8_t w = W(currentColor(0)); pos = 255 - pos; if (pos < 85) { @@ -1056,6 +1057,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ uint8_t paletteIndex = i; if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); + // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGBPalette16 curPal; curPal = currentPalette(curPal, palette); @@ -1140,7 +1142,7 @@ void WS2812FX::service() { _isServicing = true; _segment_index = 0; - Segment::handleRandomPalette(); // move it into for loop when each segment has individual random palette + for (segment &seg : _segments) { if (_suspend) return; // immediately stop processing segments if suspend requested during service() @@ -1203,6 +1205,7 @@ void WS2812FX::service() { #endif if (doShow) { yield(); + Segment::handleRandomPalette(); // slowly transtion random palette; move it into for loop when each segment has individual random palette show(); } #ifdef WLED_DEBUG @@ -1453,6 +1456,7 @@ void WS2812FX::resetSegments() { segment seg = Segment(0, _length); #endif _segments.push_back(seg); + _segments.shrink_to_fit(); // just in case ... _mainSegment = 0; } @@ -1571,18 +1575,7 @@ bool WS2812FX::checkSegmentAlignment() { return true; } -//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply) -//Note: If called in an interrupt (e.g. JSON API), original segment must be restored, -//otherwise it can lead to a crash on ESP32 because _segment_index is modified while in use by the main thread -uint8_t WS2812FX::setPixelSegment(uint8_t n) { - uint8_t prevSegId = _segment_index; - if (n < _segments.size()) { - _segment_index = n; - _virtualSegmentLength = _segments[_segment_index].virtualLength(); - } - return prevSegId; -} - +// used by analog clock overlay void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) { if (i2 < i) std::swap(i,i2); for (unsigned x = i; x <= i2; x++) setPixelColor(x, col); diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 72b4435e5..3551e0b1c 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -63,6 +63,11 @@ #define I_8266_U1_UCS_4 54 #define I_8266_DM_UCS_4 55 #define I_8266_BB_UCS_4 56 +//ESP8266 APA106 +#define I_8266_U0_APA106_3 81 +#define I_8266_U1_APA106_3 82 +#define I_8266_DM_APA106_3 83 +#define I_8266_BB_APA106_3 84 /*** ESP32 Neopixel methods ***/ //RGB @@ -100,6 +105,10 @@ #define I_32_I0_UCS_4 61 #define I_32_I1_UCS_4 62 //Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) +#define I_32_RN_APA106_3 85 +#define I_32_I0_APA106_3 86 +#define I_32_I1_APA106_3 87 +#define I_32_BB_APA106_3 88 // bitbangging on ESP32 not recommended //APA102 #define I_HS_DOT_3 39 //hardware SPI @@ -162,6 +171,11 @@ #define B_8266_U1_UCS_4 NeoPixelBusLg //4 chan, esp8266, gpio2 #define B_8266_DM_UCS_4 NeoPixelBusLg //4 chan, esp8266, gpio3 #define B_8266_BB_UCS_4 NeoPixelBusLg //4 chan, esp8266, bb (any pin) +//APA106 +#define B_8266_U0_APA106_3 NeoPixelBusLg //3 chan, esp8266, gpio1 +#define B_8266_U1_APA106_3 NeoPixelBusLg //3 chan, esp8266, gpio2 +#define B_8266_DM_APA106_3 NeoPixelBusLg //3 chan, esp8266, gpio3 +#define B_8266_BB_APA106_3 NeoPixelBusLg //3 chan, esp8266, bb (any pin but 16) #endif /*** ESP32 Neopixel methods ***/ @@ -229,6 +243,14 @@ #define B_32_I1_UCS_4 NeoPixelBusLg #endif //Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) +#define B_32_RN_APA106_3 NeoPixelBusLg +#ifndef WLED_NO_I2S0_PIXELBUS +#define B_32_I0_APA106_3 NeoPixelBusLg +#endif +#ifndef WLED_NO_I2S1_PIXELBUS +#define B_32_I1_APA106_3 NeoPixelBusLg +#endif +//#define B_32_BB_APA106_3 NeoPixelBusLg // NeoEsp8266BitBang800KbpsMethod #endif @@ -327,6 +349,10 @@ class PolyBus { case I_8266_U1_UCS_4: (static_cast(busPtr))->Begin(); break; case I_8266_DM_UCS_4: (static_cast(busPtr))->Begin(); break; case I_8266_BB_UCS_4: (static_cast(busPtr))->Begin(); break; + case I_8266_U0_APA106_3: (static_cast(busPtr))->Begin(); break; + case I_8266_U1_APA106_3: (static_cast(busPtr))->Begin(); break; + case I_8266_DM_APA106_3: (static_cast(busPtr))->Begin(); break; + case I_8266_BB_APA106_3: (static_cast(busPtr))->Begin(); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->Begin(); break; @@ -379,6 +405,14 @@ class PolyBus { case I_32_I1_UCS_4: (static_cast(busPtr))->Begin(); break; #endif // case I_32_BB_UCS_4: (static_cast(busPtr))->Begin(); break; + case I_32_RN_APA106_3: (static_cast(busPtr))->Begin(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_APA106_3: (static_cast(busPtr))->Begin(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_APA106_3: (static_cast(busPtr))->Begin(); break; + #endif +// case I_32_BB_APA106_3: (static_cast(busPtr))->Begin(); break; // ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin() case I_HS_DOT_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; case I_HS_LPD_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; @@ -427,6 +461,10 @@ class PolyBus { case I_8266_U1_UCS_4: busPtr = new B_8266_U1_UCS_4(len, pins[0]); break; case I_8266_DM_UCS_4: busPtr = new B_8266_DM_UCS_4(len, pins[0]); break; case I_8266_BB_UCS_4: busPtr = new B_8266_BB_UCS_4(len, pins[0]); break; + case I_8266_U0_APA106_3: busPtr = new B_8266_U0_APA106_3(len, pins[0]); break; + case I_8266_U1_APA106_3: busPtr = new B_8266_U1_APA106_3(len, pins[0]); break; + case I_8266_DM_APA106_3: busPtr = new B_8266_DM_APA106_3(len, pins[0]); break; + case I_8266_BB_APA106_3: busPtr = new B_8266_BB_APA106_3(len, pins[0]); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: busPtr = new B_32_RN_NEO_3(len, pins[0], (NeoBusChannel)channel); break; @@ -479,6 +517,14 @@ class PolyBus { case I_32_I1_UCS_4: busPtr = new B_32_I1_UCS_4(len, pins[0]); break; #endif // case I_32_BB_UCS_4: busPtr = new B_32_BB_UCS_4(len, pins[0], (NeoBusChannel)channel); break; + case I_32_RN_APA106_3: busPtr = new B_32_RN_APA106_3(len, pins[0], (NeoBusChannel)channel); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_APA106_3: busPtr = new B_32_I0_APA106_3(len, pins[0]); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_APA106_3: busPtr = new B_32_I1_APA106_3(len, pins[0]); break; + #endif +// case I_32_BB_APA106_3: busPtr = new B_32_BB_APA106_3(len, pins[0], (NeoBusChannel)channel); break; #endif // for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat) case I_HS_DOT_3: busPtr = new B_HS_DOT_3(len, pins[1], pins[0]); break; @@ -528,6 +574,10 @@ class PolyBus { case I_8266_U1_UCS_4: (static_cast(busPtr))->Show(consistent); break; case I_8266_DM_UCS_4: (static_cast(busPtr))->Show(consistent); break; case I_8266_BB_UCS_4: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_APA106_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_APA106_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_APA106_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_APA106_3: (static_cast(busPtr))->Show(consistent); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->Show(consistent); break; @@ -580,6 +630,14 @@ class PolyBus { case I_32_I1_UCS_4: (static_cast(busPtr))->Show(consistent); break; #endif // case I_32_BB_UCS_4: (static_cast(busPtr))->Show(consistent); break; + case I_32_RN_APA106_3: (static_cast(busPtr))->Show(consistent); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_APA106_3: (static_cast(busPtr))->Show(consistent); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_APA106_3: (static_cast(busPtr))->Show(consistent); break; + #endif +// case I_32_BB_APA106_3: (static_cast(busPtr))->Show(consistent); break; #endif case I_HS_DOT_3: (static_cast(busPtr))->Show(consistent); break; case I_SS_DOT_3: (static_cast(busPtr))->Show(consistent); break; @@ -625,6 +683,10 @@ class PolyBus { case I_8266_U0_UCS_4: return (static_cast(busPtr))->CanShow(); break; case I_8266_U1_UCS_4: return (static_cast(busPtr))->CanShow(); break; case I_8266_DM_UCS_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U0_APA106_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U1_APA106_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_DM_APA106_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_APA106_3: return (static_cast(busPtr))->CanShow(); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: return (static_cast(busPtr))->CanShow(); break; @@ -677,6 +739,14 @@ class PolyBus { case I_32_I1_UCS_4: return (static_cast(busPtr))->CanShow(); break; #endif // case I_32_BB_UCS_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_APA106_3: return (static_cast(busPtr))->CanShow(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_APA106_3: return (static_cast(busPtr))->CanShow(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_APA106_3: return (static_cast(busPtr))->CanShow(); break; + #endif +// case I_32_BB_APA106_3: return (static_cast(busPtr))->CanShow(); break; #endif case I_HS_DOT_3: return (static_cast(busPtr))->CanShow(); break; case I_SS_DOT_3: return (static_cast(busPtr))->CanShow(); break; @@ -747,6 +817,10 @@ class PolyBus { case I_8266_U1_UCS_4: (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; case I_8266_DM_UCS_4: (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; case I_8266_BB_UCS_4: (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; + case I_8266_U0_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_U1_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_DM_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_BB_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -799,6 +873,14 @@ class PolyBus { case I_32_I1_UCS_4: (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; #endif // case I_32_BB_UCS_4: (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; + case I_32_RN_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + #endif +// case I_32_BB_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; #endif case I_HS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_SS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -845,6 +927,10 @@ class PolyBus { case I_8266_U1_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_DM_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_BB_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -897,6 +983,14 @@ class PolyBus { case I_32_I1_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; #endif // case I_32_BB_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_RN_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; + #endif +// case I_32_BB_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; #endif case I_HS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; case I_SS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -944,6 +1038,10 @@ class PolyBus { case I_8266_U1_UCS_4: { Rgbw64Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break; case I_8266_DM_UCS_4: { Rgbw64Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break; case I_8266_BB_UCS_4: { Rgbw64Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break; + case I_8266_U0_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U1_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_DM_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_BB_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; @@ -996,6 +1094,14 @@ class PolyBus { case I_32_I1_UCS_4: { Rgbw64Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break; #endif // case I_32_BB_UCS_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_RN_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #endif +// case I_32_BB_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; #endif case I_HS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_SS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; @@ -1061,6 +1167,10 @@ class PolyBus { case I_8266_U1_UCS_4: delete (static_cast(busPtr)); break; case I_8266_DM_UCS_4: delete (static_cast(busPtr)); break; case I_8266_BB_UCS_4: delete (static_cast(busPtr)); break; + case I_8266_U0_APA106_3: delete (static_cast(busPtr)); break; + case I_8266_U1_APA106_3: delete (static_cast(busPtr)); break; + case I_8266_DM_APA106_3: delete (static_cast(busPtr)); break; + case I_8266_BB_APA106_3: delete (static_cast(busPtr)); break; #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: delete (static_cast(busPtr)); break; @@ -1113,6 +1223,14 @@ class PolyBus { case I_32_I1_UCS_4: delete (static_cast(busPtr)); break; #endif // case I_32_BB_UCS_4: delete (static_cast(busPtr)); break; + case I_32_RN_APA106_3: delete (static_cast(busPtr)); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_APA106_3: delete (static_cast(busPtr)); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_APA106_3: delete (static_cast(busPtr)); break; + #endif +// case I_32_BB_APA106_3: delete (static_cast(busPtr)); break; #endif case I_HS_DOT_3: delete (static_cast(busPtr)); break; case I_SS_DOT_3: delete (static_cast(busPtr)); break; @@ -1172,6 +1290,8 @@ class PolyBus { return I_8266_U0_UCS_3 + offset; case TYPE_UCS8904: return I_8266_U0_UCS_4 + offset; + case TYPE_APA106: + return I_8266_U0_APA106_3 + offset; } #else //ESP32 uint8_t offset = 0; //0 = RMT (num 0-7) 8 = I2S0 9 = I2S1 @@ -1210,6 +1330,8 @@ class PolyBus { return I_32_RN_UCS_3 + offset; case TYPE_UCS8904: return I_32_RN_UCS_4 + offset; + case TYPE_APA106: + return I_32_RN_APA106_3 + offset; } #endif } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 1234a1c5f..53c0d5290 100755 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -40,21 +40,39 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { linked_remote[12] = '\0'; #endif - JsonObject nw_ins_0 = nw["ins"][0]; - getStringFromJson(clientSSID, nw_ins_0[F("ssid")], 33); - //int nw_ins_0_pskl = nw_ins_0[F("pskl")]; - //The WiFi PSK is normally not contained in the regular file for security reasons. - //If it is present however, we will use it - getStringFromJson(clientPass, nw_ins_0["psk"], 65); + size_t n = 0; + JsonArray nw_ins = nw["ins"]; + if (!nw_ins.isNull()) { + // as password are stored separately in wsec.json when reading configuration vector resize happens there, but for dynamic config we need to resize if necessary + if (nw_ins.size() > 1 && nw_ins.size() > multiWiFi.size()) multiWiFi.resize(nw_ins.size()); // resize constructs objects while resizing + for (JsonObject wifi : nw_ins) { + JsonArray ip = wifi["ip"]; + JsonArray gw = wifi["gw"]; + JsonArray sn = wifi["sn"]; + char ssid[33] = ""; + char pass[65] = ""; + IPAddress nIP = (uint32_t)0U, nGW = (uint32_t)0U, nSN = (uint32_t)0x00FFFFFF; // little endian + getStringFromJson(ssid, wifi[F("ssid")], 33); + getStringFromJson(pass, wifi["psk"], 65); // password is not normally present but if it is, use it + for (size_t i = 0; i < 4; i++) { + CJSON(nIP[i], ip[i]); + CJSON(nGW[i], gw[i]); + CJSON(nSN[i], sn[i]); + } + if (strlen(ssid) > 0) strlcpy(multiWiFi[n].clientSSID, ssid, 33); // this will keep old SSID intact if not present in JSON + if (strlen(pass) > 0) strlcpy(multiWiFi[n].clientPass, pass, 65); // this will keep old password intact if not present in JSON + multiWiFi[n].staticIP = nIP; + multiWiFi[n].staticGW = nGW; + multiWiFi[n].staticSN = nSN; + if (++n >= WLED_MAX_WIFI_COUNT) break; + } + } - JsonArray nw_ins_0_ip = nw_ins_0["ip"]; - JsonArray nw_ins_0_gw = nw_ins_0["gw"]; - JsonArray nw_ins_0_sn = nw_ins_0["sn"]; - - for (byte i = 0; i < 4; i++) { - CJSON(staticIP[i], nw_ins_0_ip[i]); - CJSON(staticGateway[i], nw_ins_0_gw[i]); - CJSON(staticSubnet[i], nw_ins_0_sn[i]); + JsonArray dns = nw[F("dns")]; + if (!dns.isNull()) { + for (size_t i = 0; i < 4; i++) { + CJSON(dnsAddress[i], dns[i]); + } } JsonObject ap = doc["ap"]; @@ -212,7 +230,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonObject btn_obj = hw["btn"]; bool pull = btn_obj[F("pull")] | (!disablePullUp); // if true, pullup is enabled disablePullUp = !pull; - JsonArray hw_btn_ins = btn_obj[F("ins")]; + JsonArray hw_btn_ins = btn_obj["ins"]; if (!hw_btn_ins.isNull()) { for (uint8_t b = 0; b < WLED_MAX_BUTTONS; b++) { // deallocate existing button pins pinManager.deallocatePin(btnPin[b], PinOwner::Button); // does nothing if trying to deallocate a pin with PinOwner != Button @@ -433,7 +451,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (e131Port == DDP_DEFAULT_PORT) e131Port = E131_DEFAULT_PORT; // prevent double DDP port allocation CJSON(e131Multicast, if_live[F("mc")]); - JsonObject if_live_dmx = if_live[F("dmx")]; + JsonObject if_live_dmx = if_live["dmx"]; CJSON(e131Universe, if_live_dmx[F("uni")]); CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]); CJSON(DMXAddress, if_live_dmx[F("addr")]); @@ -507,6 +525,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(analogClock12pixel, ol[F("o12pix")]); CJSON(analogClock5MinuteMarks, ol[F("o5m")]); CJSON(analogClockSecondsTrail, ol[F("osec")]); + CJSON(analogClockSolidBlack, ol[F("osb")]); //timed macro rules JsonObject tm = doc[F("timers")]; @@ -665,19 +684,23 @@ void serializeConfig() { #endif JsonArray nw_ins = nw.createNestedArray("ins"); + for (size_t n = 0; n < multiWiFi.size(); n++) { + JsonObject wifi = nw_ins.createNestedObject(); + wifi[F("ssid")] = multiWiFi[n].clientSSID; + wifi[F("pskl")] = strlen(multiWiFi[n].clientPass); + JsonArray wifi_ip = wifi.createNestedArray("ip"); + JsonArray wifi_gw = wifi.createNestedArray("gw"); + JsonArray wifi_sn = wifi.createNestedArray("sn"); + for (size_t i = 0; i < 4; i++) { + wifi_ip.add(multiWiFi[n].staticIP[i]); + wifi_gw.add(multiWiFi[n].staticGW[i]); + wifi_sn.add(multiWiFi[n].staticSN[i]); + } + } - JsonObject nw_ins_0 = nw_ins.createNestedObject(); - nw_ins_0[F("ssid")] = clientSSID; - nw_ins_0[F("pskl")] = strlen(clientPass); - - JsonArray nw_ins_0_ip = nw_ins_0.createNestedArray("ip"); - JsonArray nw_ins_0_gw = nw_ins_0.createNestedArray("gw"); - JsonArray nw_ins_0_sn = nw_ins_0.createNestedArray("sn"); - - for (byte i = 0; i < 4; i++) { - nw_ins_0_ip.add(staticIP[i]); - nw_ins_0_gw.add(staticGateway[i]); - nw_ins_0_sn.add(staticSubnet[i]); + JsonArray dns = nw.createNestedArray(F("dns")); + for (size_t i = 0; i < 4; i++) { + dns.add(dnsAddress[i]); } JsonObject ap = root.createNestedObject("ap"); @@ -693,7 +716,7 @@ void serializeConfig() { ap_ip.add(2); ap_ip.add(1); - JsonObject wifi = root.createNestedObject("wifi"); + JsonObject wifi = root.createNestedObject(F("wifi")); wifi[F("sleep")] = !noWifiSleep; wifi[F("phy")] = force802_3g; @@ -721,7 +744,7 @@ void serializeConfig() { } #endif - JsonObject hw = root.createNestedObject("hw"); + JsonObject hw = root.createNestedObject(F("hw")); JsonObject hw_led = hw.createNestedObject("led"); hw_led[F("total")] = strip.getLengthTotal(); //provided for compatibility on downgrade and per-output ABL @@ -973,6 +996,7 @@ void serializeConfig() { ol[F("o12pix")] = analogClock12pixel; ol[F("o5m")] = analogClock5MinuteMarks; ol[F("osec")] = analogClockSecondsTrail; + ol[F("osb")] = analogClockSolidBlack; JsonObject timers = root.createNestedObject(F("timers")); @@ -1048,8 +1072,17 @@ bool deserializeConfigSec() { JsonObject root = pDoc->as(); - JsonObject nw_ins_0 = root["nw"]["ins"][0]; - getStringFromJson(clientPass, nw_ins_0["psk"], 65); + size_t n = 0; + JsonArray nw_ins = root["nw"]["ins"]; + if (!nw_ins.isNull()) { + if (nw_ins.size() > 1 && nw_ins.size() > multiWiFi.size()) multiWiFi.resize(nw_ins.size()); // resize constructs objects while resizing + for (JsonObject wifi : nw_ins) { + char pw[65] = ""; + getStringFromJson(pw, wifi["psk"], 65); + strlcpy(multiWiFi[n].clientPass, pw, 65); + if (++n >= WLED_MAX_WIFI_COUNT) break; + } + } JsonObject ap = root["ap"]; getStringFromJson(apPass, ap["psk"] , 65); @@ -1088,9 +1121,10 @@ void serializeConfigSec() { JsonObject nw = root.createNestedObject("nw"); JsonArray nw_ins = nw.createNestedArray("ins"); - - JsonObject nw_ins_0 = nw_ins.createNestedObject(); - nw_ins_0["psk"] = clientPass; + for (size_t i = 0; i < multiWiFi.size(); i++) { + JsonObject wifi = nw_ins.createNestedObject(); + wifi[F("psk")] = multiWiFi[i].clientPass; + } JsonObject ap = root.createNestedObject("ap"); ap["psk"] = apPass; diff --git a/wled00/const.h b/wled00/const.h index 4ef81b907..2ddfb858d 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -15,6 +15,10 @@ #define DEFAULT_MDNS_NAME "x" //increase if you need more +#ifndef WLED_MAX_WIFI_COUNT + #define WLED_MAX_WIFI_COUNT 3 +#endif + #ifndef WLED_MAX_USERMODS #ifdef ESP8266 #define WLED_MAX_USERMODS 4 @@ -157,6 +161,10 @@ #define AP_BEHAVIOR_NO_CONN 1 //Open when no connection (either after boot or if connection is lost) #define AP_BEHAVIOR_ALWAYS 2 //Always open #define AP_BEHAVIOR_BUTTON_ONLY 3 //Only when button pressed for 6 sec +#define AP_BEHAVIOR_TEMPORARY 4 //Open AP when no connection after boot but only temporary +#ifndef WLED_AP_TIMEOUT + #define WLED_AP_TIMEOUT 300000 //Temporary AP timeout +#endif //Notifier callMode #define CALL_MODE_INIT 0 //no updates on init, can be used to disable updates @@ -235,6 +243,7 @@ #define TYPE_WS2811_400KHZ 24 //half-speed WS2812 protocol, used by very old WS2811 units #define TYPE_TM1829 25 #define TYPE_UCS8903 26 +#define TYPE_APA106 27 #define TYPE_UCS8904 29 //first RGBW digital type (hardcoded in busmanager.cpp, memUsage()) #define TYPE_SK6812_RGBW 30 #define TYPE_TM1814 31 @@ -292,19 +301,20 @@ #define BTN_TYPE_TOUCH_SWITCH 9 //Ethernet board types -#define WLED_NUM_ETH_TYPES 11 +#define WLED_NUM_ETH_TYPES 12 -#define WLED_ETH_NONE 0 -#define WLED_ETH_WT32_ETH01 1 -#define WLED_ETH_ESP32_POE 2 -#define WLED_ETH_WESP32 3 -#define WLED_ETH_QUINLED 4 -#define WLED_ETH_TWILIGHTLORD 5 -#define WLED_ETH_ESP32DEUX 6 -#define WLED_ETH_ESP32ETHKITVE 7 -#define WLED_ETH_QUINLED_OCTA 8 -#define WLED_ETH_ABCWLEDV43ETH 9 -#define WLED_ETH_SERG74 10 +#define WLED_ETH_NONE 0 +#define WLED_ETH_WT32_ETH01 1 +#define WLED_ETH_ESP32_POE 2 +#define WLED_ETH_WESP32 3 +#define WLED_ETH_QUINLED 4 +#define WLED_ETH_TWILIGHTLORD 5 +#define WLED_ETH_ESP32DEUX 6 +#define WLED_ETH_ESP32ETHKITVE 7 +#define WLED_ETH_QUINLED_OCTA 8 +#define WLED_ETH_ABCWLEDV43ETH 9 +#define WLED_ETH_SERG74 10 +#define WLED_ETH_ESP32_POE_WROVER 11 //Hue error codes #define HUE_ERROR_INACTIVE 0 diff --git a/wled00/data/index.css b/wled00/data/index.css index 095de572a..dc44ef1af 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -863,6 +863,15 @@ input[type=range]::-moz-range-thumb { margin: 0; white-space: nowrap; } +a.btn { + display: block; + white-space: nowrap; + text-align: center; + padding: 8px 32px; + position: relative; + box-sizing: border-box; + line-height: 24px; +} /* Quick color select wrapper div */ #qcs-w { @@ -1018,7 +1027,7 @@ textarea { width: 50px !important; } -.segname, .pname, .bname { +.segname, .pname { white-space: nowrap; text-align: center; overflow: hidden; @@ -1028,9 +1037,6 @@ textarea { max-width: 170px; position: relative; } -.bname { - padding: 0 24px; -} .segname .flr, .pname .flr { transform: rotate(0deg); @@ -1520,7 +1526,7 @@ dialog { #info .infobtn, #nodes .infobtn { width: 145px; } - #info div, #nodes div { + #info div, #nodes div, #nodes a.btn { max-width: 320px; } } diff --git a/wled00/data/index.htm b/wled00/data/index.htm index ae685bdb9..c735f00d0 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -46,89 +46,89 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-

-
-
-
-
-
R
+
+
+
+
+
+

+
+
+
+
+
R
- - - + + +

- +
- - - + + +

Color palette

@@ -159,27 +159,27 @@
-
- -
+ +
- -
+ +
@@ -216,7 +216,7 @@
-
+
@@ -224,7 +224,7 @@
-
+
@@ -232,22 +232,22 @@
-
+
-
Countdown Mode:
Countdown Goal:
diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 24e6000cc..63e17a597 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -8,7 +8,7 @@ var d = document; var loc = false, locip, locproto = "http:"; var scanLoops = 0, preScanSSID = ""; - + var maxNetworks = 3; function gId(e) { return d.getElementById(e); } function cE(e) { return d.createElement(e); } function toggle(el){gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide");} @@ -52,13 +52,14 @@ } scanLoops = 0; - let cs = gId("CS"); - if (cs) { + let cs = d.querySelectorAll("#wifi_entries input[type=text]"); + for (let input of (cs||[])) { + let found = false; let select = cE("select"); - select.setAttribute("id", "CS"); - select.setAttribute("name", "CS"); - select.setAttribute("onchange", "T()"); - preScanSSID = cs.value; + select.id = input.id; + select.name = input.name; + select.setAttribute("onchange", "T(this)"); + preScanSSID = input.value; for (let i = 0; i < select.children.length; i++) { select.removeChild(select.children[i]); @@ -70,8 +71,9 @@ option.setAttribute("value", networks[i].ssid); option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm)`; - if (networks[i].ssid === cs.value) { + if (networks[i].ssid === input.value) { option.setAttribute("selected", "selected"); + found = true; } select.appendChild(option); @@ -79,10 +81,11 @@ const option = cE("option"); option.setAttribute("value", "!Cs"); - option.textContent = `Other network...`; + option.textContent = "Other network..."; select.appendChild(option); - cs.replaceWith(select); + if (input.value === "" || found) input.replaceWith(select); + else select.remove(); } button.disabled = false; @@ -90,17 +93,48 @@ }); } // replace WiFi select with custom SSID input field again - function T() { - let cs = gId("CS"); + function T(cs) { if (!cs || cs.value != "!Cs") return; let input = cE("input"); input.type = "text"; - input.id = "CS"; - input.name ="CS"; + input.id = cs.id; + input.name = cs.name; input.setAttribute("maxlength",32); input.value = preScanSSID; cs.replaceWith(input); } + function resetWiFi(maxN = undefined) { + if (maxN) maxNetworks = maxN; + let entries = gId("wifi_entries").children + for (let i = entries.length; i > 0; i--) entries[i-1].remove(); + btnWiFi(0); + } + function btnWiFi(i) { + gId("wifi_add").style.display = (i1) ? "inline":"none"; + } + function addWiFi(ssid="",pass="",ip=0,gw=0,sn=0x00ffffff) { // little endian + var i = gId("wifi_entries").childNodes.length; + if (i >= maxNetworks) return; + var b = `

+Network name (SSID${i==0?", empty to not connect":""}):
0?"required":""}>
+Network password:

+Static IP (leave at 0.0.0.0 for DHCP)${i==0?"
Also used by Ethernet":""}:
+...
+Static gateway:
+...
+Static subnet mask:
+...
`; + gId("wifi_entries").insertAdjacentHTML("beforeend", b); + btnWiFi(i+1); + } + function remWiFi() { + const entries = gId("wifi_entries").children; + const i = entries.length; + if (i < 2) return; + entries[i-1].remove(); + btnWiFi(i-1); + } // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript function loadJS(FILE_URL, async = true) { let scE = cE("script"); @@ -158,24 +192,16 @@

WiFi setup

Connect to existing network


- Network name (SSID, empty to not connect):
-
- Network password:

- Static IP (leave at 0.0.0.0 for DHCP):
- . - . - . -
- Static gateway:
- . - . - . -
- Static subnet mask:
- . - . - . -
+
+ Wireless networks +
+
+ +
+
+ DNS server address:
+ ...
+
mDNS address (leave empty for no mDNS):
http:// .local
Client IP: Not connected
@@ -186,10 +212,12 @@ Access Point WiFi channel:
AP opens:
+ + + + + +
AP IP: Not active

Experimental

Force 802.11g mode (ESP8266 only):
@@ -215,6 +243,7 @@ + diff --git a/wled00/data/style.css b/wled00/data/style.css index 52b26a825..b6cb0f9e6 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -81,6 +81,7 @@ input:disabled { } input[type="text"], input[type="number"], +input[type="password"], select { font-size: medium; margin: 2px; diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 68c7ca5a5..c9fe350be 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -490,7 +490,7 @@ void prepareArtnetPollReply(ArtPollReply *reply) { // Node is DHCP capable // Node supports 15 bit Port-Address (Art-Net 3 or 4) // Node is able to switch between ArtNet and sACN - reply->reply_status_2 = (staticIP[0] == 0) ? 0x1F : 0x1D; + reply->reply_status_2 = (multiWiFi[0].staticIP[0] == 0) ? 0x1F : 0x1D; // RDM is disabled // Output style is continuous diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index e256ceb5f..bb24725d9 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -48,6 +48,21 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau return true; } +typedef struct WiFiConfig { + char clientSSID[33]; + char clientPass[65]; + IPAddress staticIP; + IPAddress staticGW; + IPAddress staticSN; + WiFiConfig(const char *ssid="", const char *pass="", uint32_t ip=0, uint32_t gw=0, uint32_t subnet=0x00FFFFFF) // little endian + : staticIP(ip) + , staticGW(gw) + , staticSN(subnet) + { + strncpy(clientSSID, ssid, 32); clientSSID[32] = 0; + strncpy(clientPass, pass, 64); clientPass[64] = 0; + } +} wifi_config; //colors.cpp // similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) diff --git a/wled00/file.cpp b/wled00/file.cpp index 4edbdd6fb..fc3dc7eeb 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -377,27 +377,27 @@ void updateFSInfo() { //Un-comment any file types you need static String getContentType(AsyncWebServerRequest* request, String filename){ - if(request->hasArg("download")) return "application/octet-stream"; - else if(filename.endsWith(".htm")) return "text/html"; - else if(filename.endsWith(".html")) return "text/html"; - else if(filename.endsWith(".css")) return "text/css"; - else if(filename.endsWith(".js")) return "application/javascript"; - else if(filename.endsWith(".json")) return "application/json"; - else if(filename.endsWith(".png")) return "image/png"; - else if(filename.endsWith(".gif")) return "image/gif"; - else if(filename.endsWith(".jpg")) return "image/jpeg"; - else if(filename.endsWith(".ico")) return "image/x-icon"; -// else if(filename.endsWith(".xml")) return "text/xml"; -// else if(filename.endsWith(".pdf")) return "application/x-pdf"; -// else if(filename.endsWith(".zip")) return "application/x-zip"; -// else if(filename.endsWith(".gz")) return "application/x-gzip"; + if(request->hasArg(F("download"))) return SET_F("application/octet-stream"); + else if(filename.endsWith(F(".htm"))) return SET_F("text/html"); + else if(filename.endsWith(F(".html"))) return SET_F("text/html"); + else if(filename.endsWith(F(".css"))) return SET_F("text/css"); + else if(filename.endsWith(F(".js"))) return SET_F("application/javascript"); + else if(filename.endsWith(F(".json"))) return SET_F("application/json"); + else if(filename.endsWith(F(".png"))) return SET_F("image/png"); + else if(filename.endsWith(F(".gif"))) return SET_F("image/gif"); + else if(filename.endsWith(F(".jpg"))) return SET_F("image/jpeg"); + else if(filename.endsWith(F(".ico"))) return SET_F("image/x-icon"); +// else if(filename.endsWith(F(".xml"))) return SET_F("text/xml"); +// else if(filename.endsWith(F(".pdf"))) return SET_F("application/x-pdf"); +// else if(filename.endsWith(F(".zip"))) return SET_F("application/x-zip"); +// else if(filename.endsWith(F(".gz"))) return SET_F("application/x-gzip"); return "text/plain"; } bool handleFileRead(AsyncWebServerRequest* request, String path){ DEBUG_PRINTLN("WS FileRead: " + path); if(path.endsWith("/")) path += "index.htm"; - if(path.indexOf("sec") > -1) return false; + if(path.indexOf(F("sec")) > -1) return false; String contentType = getContentType(request, path); /*String pathWithGz = path + ".gz"; if(WLED_FS.exists(pathWithGz)){ diff --git a/wled00/improv.cpp b/wled00/improv.cpp index 695d07ff7..f7867117f 100644 --- a/wled00/improv.cpp +++ b/wled00/improv.cpp @@ -259,14 +259,14 @@ void parseWiFiCommand(char* rpcData) { uint8_t ssidLen = rpcData[1]; if (ssidLen > len -1 || ssidLen > 32) return; - memset(clientSSID, 0, 32); - memcpy(clientSSID, rpcData+2, ssidLen); + memset(multiWiFi[0].clientSSID, 0, 32); + memcpy(multiWiFi[0].clientSSID, rpcData+2, ssidLen); - memset(clientPass, 0, 64); + memset(multiWiFi[0].clientPass, 0, 64); if (len > ssidLen +1) { uint8_t passLen = rpcData[2+ssidLen]; - memset(clientPass, 0, 64); - memcpy(clientPass, rpcData+3+ssidLen, passLen); + memset(multiWiFi[0].clientPass, 0, 64); + memcpy(multiWiFi[0].clientPass, rpcData+3+ssidLen, passLen); } sendImprovStateResponse(0x03); //provisioning diff --git a/wled00/json.cpp b/wled00/json.cpp index 395ee7cbc..2213dd5b1 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -470,6 +470,19 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } } + JsonObject wifi = root[F("wifi")]; + if (!wifi.isNull()) { + bool apMode = getBoolVal(wifi[F("ap")], apActive); + if (!apActive && apMode) WLED::instance().initAP(); // start AP mode immediately + else if (apActive && !apMode) { // stop AP mode immediately + dnsServer.stop(); + WiFi.softAPdisconnect(true); + apActive = false; + } + //bool restart = wifi[F("restart")] | false; + //if (restart) forceReconnect = true; + } + stateUpdated(callMode); if (presetToRestore) currentPreset = presetToRestore; @@ -611,7 +624,7 @@ void serializeInfo(JsonObject root) root[F("vid")] = VERSION; root[F("cn")] = F(WLED_CODENAME); - JsonObject leds = root.createNestedObject("leds"); + JsonObject leds = root.createNestedObject(F("leds")); leds[F("count")] = strip.getLengthTotal(); leds[F("pwr")] = BusManager::currentMilliamps(); leds["fps"] = strip.getFps(); @@ -622,7 +635,7 @@ void serializeInfo(JsonObject root) #ifndef WLED_DISABLE_2D if (strip.isMatrix) { - JsonObject matrix = leds.createNestedObject("matrix"); + JsonObject matrix = leds.createNestedObject(F("matrix")); matrix["w"] = Segment::maxWidth; matrix["h"] = Segment::maxHeight; } @@ -702,7 +715,7 @@ void serializeInfo(JsonObject root) } } - JsonObject wifi_info = root.createNestedObject("wifi"); + JsonObject wifi_info = root.createNestedObject(F("wifi")); wifi_info[F("bssid")] = WiFi.BSSIDstr(); int qrssi = WiFi.RSSI(); wifi_info[F("rssi")] = qrssi; diff --git a/wled00/network.cpp b/wled00/network.cpp index 1b02d0c5d..2ae38f799 100644 --- a/wled00/network.cpp +++ b/wled00/network.cpp @@ -123,6 +123,16 @@ const ethernet_settings ethernetBoards[] = { 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, ETH_CLOCK_GPIO17_OUT // eth_clk_mode + }, + + // ESP32-POE-WROVER + { + 0, // eth_address, + 12, // eth_power, + 23, // eth_mdc, + 18, // eth_mdio, + ETH_PHY_LAN8720, // eth_type, + ETH_CLOCK_GPIO0_OUT // eth_clk_mode } }; #endif @@ -163,8 +173,8 @@ void WiFiEvent(WiFiEvent_t event) if (!apActive) { WiFi.disconnect(true); } - if (staticIP != (uint32_t)0x00000000 && staticGateway != (uint32_t)0x00000000) { - ETH.config(staticIP, staticGateway, staticSubnet, IPAddress(8, 8, 8, 8)); + if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) { + ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress); } else { ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); } diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index f065cd36a..19b26c224 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -89,6 +89,16 @@ void _overlayAnalogCountdown() void handleOverlayDraw() { usermods.handleOverlayDraw(); + if (analogClockSolidBlack) { + const Segment* segments = strip.getSegments(); + for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) { + const Segment& segment = segments[i]; + if (!segment.isActive()) continue; + if (segment.mode > 0 || segment.colors[0] > 0) { + return; + } + } + } if (overlayCurrent == 1) _overlayAnalogClock(); } diff --git a/wled00/set.cpp b/wled00/set.cpp index e83911783..49a54ab25 100755 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -19,21 +19,52 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) //WIFI SETTINGS if (subPage == SUBPAGE_WIFI) { - char oldSSID[sizeof(clientSSID)]; + unsigned cnt = 0; + for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) { + char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID + char pw[4] = "PW"; pw[2] = 48+n; pw[3] = 0; //client password + char ip[5] = "IP"; ip[2] = 48+n; ip[4] = 0; //IP address + char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address + char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask + if (request->hasArg(cs)) { + if (n >= multiWiFi.size()) multiWiFi.push_back(WiFiConfig()); // expand vector by one + char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID); + char oldPass[65]; strcpy(oldPass, multiWiFi[n].clientPass); - strcpy(oldSSID, clientSSID); - strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33); - if (!strcmp(oldSSID, clientSSID)) forceReconnect = true; + strlcpy(multiWiFi[n].clientSSID, request->arg(cs).c_str(), 33); + if (strlen(oldSSID) == 0 || !strncmp(multiWiFi[n].clientSSID, oldSSID, 32)) { + forceReconnect = true; + } + if (!isAsterisksOnly(request->arg(pw).c_str(), 65)) { + strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65); + forceReconnect = true; + } + for (size_t i = 0; i < 4; i++) { + ip[3] = 48+i; + gw[3] = 48+i; + sn[3] = 48+i; + multiWiFi[n].staticIP[i] = request->arg(ip).toInt(); + multiWiFi[n].staticGW[i] = request->arg(gw).toInt(); + multiWiFi[n].staticSN[i] = request->arg(sn).toInt(); + } + cnt++; + } + } + // remove unused + if (cnt < multiWiFi.size()) { + cnt = multiWiFi.size() - cnt; + while (cnt--) multiWiFi.pop_back(); + multiWiFi.shrink_to_fit(); // release memory + } - if (!isAsterisksOnly(request->arg(F("CP")).c_str(), 65)) { - strlcpy(clientPass, request->arg(F("CP")).c_str(), 65); - forceReconnect = true; + if (request->hasArg(F("D0"))) { + dnsAddress = IPAddress(request->arg(F("D0")).toInt(),request->arg(F("D1")).toInt(),request->arg(F("D2")).toInt(),request->arg(F("D3")).toInt()); } strlcpy(cmDNS, request->arg(F("CM")).c_str(), 33); apBehavior = request->arg(F("AB")).toInt(); - strcpy(oldSSID, apSSID); + char oldSSID[33]; strcpy(oldSSID, apSSID); strlcpy(apSSID, request->arg(F("AS")).c_str(), 33); if (!strcmp(oldSSID, apSSID) && apActive) forceReconnect = true; apHide = request->hasArg(F("AH")); @@ -61,21 +92,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) ethernetType = request->arg(F("ETH")).toInt(); WLED::instance().initEthernet(); #endif - - char k[3]; k[2] = 0; - for (int i = 0; i<4; i++) - { - k[1] = i+48;//ascii 0,1,2,3 - - k[0] = 'I'; //static IP - staticIP[i] = request->arg(k).toInt(); - - k[0] = 'G'; //gateway - staticGateway[i] = request->arg(k).toInt(); - - k[0] = 'S'; //subnet - staticSubnet[i] = request->arg(k).toInt(); - } } //LED SETTINGS @@ -440,6 +456,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) analogClock12pixel = request->arg(F("OM")).toInt(); analogClock5MinuteMarks = request->hasArg(F("O5")); analogClockSecondsTrail = request->hasArg(F("OS")); + analogClockSolidBlack = request->hasArg(F("OB")); countdownMode = request->hasArg(F("CE")); countdownYear = request->arg(F("CY")).toInt(); diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 6268aa983..4a03d4847 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -170,7 +170,7 @@ #endif #ifdef USERMOD_KLIPPER_PERCENTAGE - #include "..\usermods\usermod_v2_klipper_percentage\usermod_v2_klipper_percentage.h" + #include "../usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h" #endif #ifdef USERMOD_BOBLIGHT diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 967192efe..cc42e9dd5 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -34,6 +34,8 @@ void WLED::reset() void WLED::loop() { + static uint32_t lastHeap = UINT32_MAX; + static unsigned long heapTime = 0; #ifdef WLED_DEBUG static unsigned long lastRun = 0; unsigned long loopMillis = millis(); @@ -151,6 +153,21 @@ void WLED::loop() createEditHandler(false); } + // reconnect WiFi to clear stale allocations if heap gets too low + if (millis() - heapTime > 15000) { + uint32_t heap = ESP.getFreeHeap(); + if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) { + DEBUG_PRINT(F("Heap too low! ")); DEBUG_PRINTLN(heap); + forceReconnect = true; + strip.resetSegments(); // remove all but one segments from memory + } else if (heap < MIN_HEAP_SIZE) { + DEBUG_PRINTLN(F("Heap low, purging segments.")); + strip.purgeSegments(); + } + lastHeap = heap; + heapTime = millis(); + } + //LED settings have been saved, re-init busses //This code block causes severe FPS drop on ESP32 with the original "if (busConfigs[0] != nullptr)" conditional. Investigate! if (doInitBusses) { @@ -386,7 +403,7 @@ void WLED::setup() //DEBUG_PRINT(F("LEDs inited. heap usage ~")); //DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); -#ifdef WLED_DEBUG +#if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) pinManager.allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output #endif #ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin @@ -424,6 +441,7 @@ void WLED::setup() escapedMac.toLowerCase(); WLED_SET_AP_SSID(); // otherwise it is empty on first boot until config is saved + multiWiFi.push_back(WiFiConfig(CLIENT_SSID,CLIENT_PASS)); // initialise vector with default WiFi DEBUG_PRINTLN(F("Reading config")); deserializeConfigFromFS(); @@ -445,13 +463,16 @@ void WLED::setup() usermods.setup(); DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); - if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0) + if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0) showWelcomePage = true; WiFi.persistent(false); #ifdef WLED_USE_ETHERNET WiFi.onEvent(WiFiEvent); #endif + WiFi.mode(WIFI_STA); // enable scanning + findWiFi(true); // start scanning for available WiFi-s + #ifdef WLED_ENABLE_ADALIGHT //Serial RX (Adalight, Improv, Serial JSON) only possible if GPIO3 unused //Serial TX (Debug, Improv, Serial JSON) only possible if GPIO1 unused @@ -697,11 +718,52 @@ bool WLED::initEthernet() #else return false; // Ethernet not enabled for build #endif +} +// performs asynchronous scan for available networks (which may take couple of seconds to finish) +// returns configured WiFi ID with the strongest signal (or default if no configured networks available) +int8_t WLED::findWiFi(bool doScan) { + if (multiWiFi.size() <= 1) { + DEBUG_PRINTLN(F("Defaulf WiFi used.")); + return 0; + } + + if (doScan) WiFi.scanDelete(); // restart scan + + int status = WiFi.scanComplete(); // complete scan may take as much as several seconds (usually <3s with not very crowded air) + + if (status == WIFI_SCAN_FAILED) { + DEBUG_PRINTLN(F("WiFi scan started.")); + WiFi.scanNetworks(true); // start scanning in asynchronous mode + } else if (status >= 0) { // status contains number of found networks + DEBUG_PRINT(F("WiFi scan completed: ")); DEBUG_PRINTLN(status); + int rssi = -9999; + int selected = selectedWiFi; + for (int o = 0; o < status; o++) { + DEBUG_PRINT(F(" WiFi available: ")); DEBUG_PRINT(WiFi.SSID(o)); + DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(WiFi.RSSI(o)); DEBUG_PRINTLN(F("dB")); + for (unsigned n = 0; n < multiWiFi.size(); n++) + if (!strcmp(WiFi.SSID(o).c_str(), multiWiFi[n].clientSSID)) { + // find the WiFi with the strongest signal (but keep priority of entry if signal difference is not big) + if ((n < selected && WiFi.RSSI(o) > rssi-10) || WiFi.RSSI(o) > rssi) { + rssi = WiFi.RSSI(o); + selected = n; + } + break; + } + } + DEBUG_PRINT(F("Selected: ")); DEBUG_PRINT(multiWiFi[selected].clientSSID); + DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(rssi); DEBUG_PRINTLN(F("dB")); + return selected; + } + //DEBUG_PRINT(F("WiFi scan running.")); + return status; // scan is still running or there was an error } void WLED::initConnection() { + DEBUG_PRINTLN(F("initConnection() called.")); + #ifdef WLED_ENABLE_WEBSOCKETS ws.onEvent(wsEvent); #endif @@ -714,13 +776,13 @@ void WLED::initConnection() } #endif - WiFi.disconnect(true); // close old connections + WiFi.disconnect(true); // close old connections #ifdef ESP8266 WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N); #endif - if (staticIP[0] != 0 && staticGateway[0] != 0) { - WiFi.config(staticIP, staticGateway, staticSubnet, IPAddress(1, 1, 1, 1)); + if (multiWiFi[selectedWiFi].staticIP != 0U && multiWiFi[selectedWiFi].staticGW != 0U) { + WiFi.config(multiWiFi[selectedWiFi].staticIP, multiWiFi[selectedWiFi].staticGW, multiWiFi[selectedWiFi].staticSN, dnsAddress); } else { WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0)); } @@ -745,13 +807,14 @@ void WLED::initConnection() showWelcomePage = false; DEBUG_PRINT(F("Connecting to ")); - DEBUG_PRINT(clientSSID); + DEBUG_PRINT(multiWiFi[selectedWiFi].clientSSID); DEBUG_PRINTLN("..."); // convert the "serverDescription" into a valid DNS hostname (alphanumeric) char hostname[25]; prepareHostname(hostname); - WiFi.begin(clientSSID, clientPass); + WiFi.begin(multiWiFi[selectedWiFi].clientSSID, multiWiFi[selectedWiFi].clientPass); // no harm if called multiple times + #ifdef ARDUINO_ARCH_ESP32 #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) WiFi.setTxPower(WIFI_POWER_8_5dBm); @@ -843,35 +906,26 @@ void WLED::initInterfaces() void WLED::handleConnection() { + static bool scanDone = true; static byte stacO = 0; - static uint32_t lastHeap = UINT32_MAX; - static unsigned long heapTime = 0; unsigned long now = millis(); + const bool wifiConfigured = WLED_WIFI_CONFIGURED; - if (now < 2000 && (!WLED_WIFI_CONFIGURED || apBehavior == AP_BEHAVIOR_ALWAYS)) + // ignore connection handling if WiFi is configured and scan still running + // or within first 2s if WiFi is not configured or AP is always active + if ((wifiConfigured && multiWiFi.size() > 1 && WiFi.scanComplete() < 0) || (now < 2000 && (!wifiConfigured || apBehavior == AP_BEHAVIOR_ALWAYS))) return; - if (lastReconnectAttempt == 0) { - DEBUG_PRINTLN(F("lastReconnectAttempt == 0")); + if (lastReconnectAttempt == 0 || forceReconnect) { + DEBUG_PRINTLN(F("Initial connect or forced reconnect.")); + selectedWiFi = findWiFi(); // find strongest WiFi initConnection(); + interfacesInited = false; + forceReconnect = false; + wasConnected = false; return; } - // reconnect WiFi to clear stale allocations if heap gets too low - if (now - heapTime > 5000) { - uint32_t heap = ESP.getFreeHeap(); - if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) { - DEBUG_PRINT(F("Heap too low! ")); - DEBUG_PRINTLN(heap); - forceReconnect = true; - strip.resetSegments(); - } else if (heap < MIN_HEAP_SIZE) { - strip.purgeSegments(); - } - lastHeap = heap; - heapTime = now; - } - byte stac = 0; if (apActive) { #ifdef ESP8266 @@ -885,7 +939,7 @@ void WLED::handleConnection() stacO = stac; DEBUG_PRINT(F("Connected AP clients: ")); DEBUG_PRINTLN(stac); - if (!WLED_CONNECTED && WLED_WIFI_CONFIGURED) { // trying to connect, but not connected + if (!WLED_CONNECTED && wifiConfigured) { // trying to connect, but not connected if (stac) WiFi.disconnect(); // disable search so that AP can work else @@ -893,36 +947,49 @@ void WLED::handleConnection() } } } - if (forceReconnect) { - DEBUG_PRINTLN(F("Forcing reconnect.")); - initConnection(); - interfacesInited = false; - forceReconnect = false; - wasConnected = false; - return; - } + if (!Network.isConnected()) { if (interfacesInited) { + if (scanDone && multiWiFi.size() > 1) { + DEBUG_PRINTLN(F("WiFi scan initiated on disconnect.")); + findWiFi(true); // reinit scan + scanDone = false; + return; // try to connect in next iteration + } DEBUG_PRINTLN(F("Disconnected!")); + selectedWiFi = findWiFi(); initConnection(); interfacesInited = false; + scanDone = true; } //send improv failed 6 seconds after second init attempt (24 sec. after provisioning) if (improvActive > 2 && now - lastReconnectAttempt > 6000) { sendImprovStateResponse(0x03, true); improvActive = 2; } - if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && WLED_WIFI_CONFIGURED) { + if (now - lastReconnectAttempt > ((stac) ? 300000 : 18000) && wifiConfigured) { if (improvActive == 2) improvActive = 3; DEBUG_PRINTLN(F("Last reconnect too old.")); + if (++selectedWiFi >= multiWiFi.size()) selectedWiFi = 0; // we couldn't connect, try with another network from the list initConnection(); } if (!apActive && now - lastReconnectAttempt > 12000 && (!wasConnected || apBehavior == AP_BEHAVIOR_NO_CONN)) { - DEBUG_PRINTLN(F("Not connected AP.")); - initAP(); + if (!(apBehavior == AP_BEHAVIOR_TEMPORARY && now > WLED_AP_TIMEOUT)) { + DEBUG_PRINTLN(F("Not connected AP.")); + initAP(); // start AP only within first 5min + } + } + if (apActive && apBehavior == AP_BEHAVIOR_TEMPORARY && now > WLED_AP_TIMEOUT && stac == 0) { // disconnect AP after 5min if no clients connected + // if AP was enabled more than 10min after boot or if client was connected more than 10min after boot do not disconnect AP mode + if (now < 2*WLED_AP_TIMEOUT) { + dnsServer.stop(); + WiFi.softAPdisconnect(true); + apActive = false; + DEBUG_PRINTLN(F("Temporary AP disabled.")); + } } } else if (!interfacesInited) { //newly connected - DEBUG_PRINTLN(""); + DEBUG_PRINTLN(); DEBUG_PRINT(F("Connected! IP address: ")); DEBUG_PRINTLN(Network.localIP()); if (improvActive) { @@ -940,7 +1007,7 @@ void WLED::handleConnection() dnsServer.stop(); WiFi.softAPdisconnect(true); apActive = false; - DEBUG_PRINTLN(F("Access point disabled (handle).")); + DEBUG_PRINTLN(F("Access point disabled (connected).")); } } } diff --git a/wled00/wled.h b/wled00/wled.h index 79488e8e8..f9027c4f9 100755 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2401140 +#define VERSION 2401270 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -304,22 +304,21 @@ WLED_GLOBAL int8_t irPin _INIT(IRPIN); WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use // WiFi CONFIG (all these can be changed via web UI, no need to set them here) -WLED_GLOBAL char clientSSID[33] _INIT(CLIENT_SSID); -WLED_GLOBAL char clientPass[65] _INIT(CLIENT_PASS); -WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) -WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) -WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13) -WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID -WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default -WLED_GLOBAL IPAddress staticIP _INIT_N((( 0, 0, 0, 0))); // static IP of ESP -WLED_GLOBAL IPAddress staticGateway _INIT_N((( 0, 0, 0, 0))); // gateway (router) IP -WLED_GLOBAL IPAddress staticSubnet _INIT_N(((255, 255, 255, 0))); // most common subnet in home networks +WLED_GLOBAL uint8_t selectedWiFi _INIT(0); +WLED_GLOBAL std::vector multiWiFi; +WLED_GLOBAL IPAddress dnsAddress _INIT_N((( 8, 8, 8, 8))); // Google's DNS +WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) +WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) +WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13) +WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID +WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default #ifdef ARDUINO_ARCH_ESP32 -WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues +WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues #else WLED_GLOBAL bool noWifiSleep _INIT(false); #endif WLED_GLOBAL bool force802_3g _INIT(false); +#define WLED_WIFI_CONFIGURED (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) != 0) #ifdef WLED_USE_ETHERNET #ifdef WLED_ETH_DEFAULT // default ethernet board type if specified @@ -494,6 +493,7 @@ WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel WLED_GLOBAL bool analogClock5MinuteMarks _INIT(false); // Light pixels at every 5-minute position +WLED_GLOBAL bool analogClockSolidBlack _INIT(false); // Show clock overlay only if all LEDs are solid black (effect is 0 and color is black) WLED_GLOBAL bool countdownMode _INIT(false); // Clock will count down towards date WLED_GLOBAL byte countdownYear _INIT(20), countdownMonth _INIT(1); // Countdown target date, year is last two digits @@ -833,7 +833,6 @@ WLED_GLOBAL volatile uint8_t jsonBufferLock _INIT(0); #else #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) #endif -#define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0) #ifndef WLED_AP_SSID_UNIQUE #define WLED_SET_AP_SSID() do { \ @@ -883,6 +882,7 @@ public: void initAP(bool resetAP = false); void initConnection(); void initInterfaces(); + int8_t findWiFi(bool doScan = false); #if defined(STATUSLED) void handleStatusLED(); #endif diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index 9ea838797..89e5d65c4 100755 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -74,11 +74,11 @@ void loadSettingsFromEEPROM() int lastEEPROMversion = EEPROM.read(377); //last EEPROM version before update - readStringFromEEPROM( 0, clientSSID, 32); - readStringFromEEPROM( 32, clientPass, 64); - readStringFromEEPROM( 96, cmDNS, 32); - readStringFromEEPROM(128, apSSID, 32); - readStringFromEEPROM(160, apPass, 64); + readStringFromEEPROM( 0, multiWiFi[0].clientSSID, 32); + readStringFromEEPROM( 32, multiWiFi[0].clientPass, 64); + readStringFromEEPROM( 96, cmDNS, 32); + readStringFromEEPROM(128, apSSID, 32); + readStringFromEEPROM(160, apPass, 64); nightlightDelayMinsDefault = EEPROM.read(224); nightlightDelayMins = nightlightDelayMinsDefault; diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 82cc55014..57e0c84b9 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -532,18 +532,18 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { const String& url = request->url(); if (url.indexOf("sett") >= 0) { - if (url.indexOf(".js") > 0) subPage = SUBPAGE_JS; - else if (url.indexOf(".css") > 0) subPage = SUBPAGE_CSS; - else if (url.indexOf("wifi") > 0) subPage = SUBPAGE_WIFI; - else if (url.indexOf("leds") > 0) subPage = SUBPAGE_LEDS; - else if (url.indexOf("ui") > 0) subPage = SUBPAGE_UI; - else if (url.indexOf("sync") > 0) subPage = SUBPAGE_SYNC; - else if (url.indexOf("time") > 0) subPage = SUBPAGE_TIME; - else if (url.indexOf("sec") > 0) subPage = SUBPAGE_SEC; - else if (url.indexOf("dmx") > 0) subPage = SUBPAGE_DMX; - else if (url.indexOf("um") > 0) subPage = SUBPAGE_UM; - else if (url.indexOf("2D") > 0) subPage = SUBPAGE_2D; - else if (url.indexOf("lock") > 0) subPage = SUBPAGE_LOCK; + if (url.indexOf(F(".js")) > 0) subPage = SUBPAGE_JS; + else if (url.indexOf(F(".css")) > 0) subPage = SUBPAGE_CSS; + else if (url.indexOf(F("wifi")) > 0) subPage = SUBPAGE_WIFI; + else if (url.indexOf(F("leds")) > 0) subPage = SUBPAGE_LEDS; + else if (url.indexOf(F("ui")) > 0) subPage = SUBPAGE_UI; + else if (url.indexOf( "sync") > 0) subPage = SUBPAGE_SYNC; + else if (url.indexOf( "time") > 0) subPage = SUBPAGE_TIME; + else if (url.indexOf(F("sec")) > 0) subPage = SUBPAGE_SEC; + else if (url.indexOf( "dmx") > 0) subPage = SUBPAGE_DMX; + else if (url.indexOf( "um") > 0) subPage = SUBPAGE_UM; + else if (url.indexOf( "2D") > 0) subPage = SUBPAGE_2D; + else if (url.indexOf(F("lock")) > 0) subPage = SUBPAGE_LOCK; } else if (url.indexOf("/update") >= 0) subPage = SUBPAGE_UPDATE; // update page, for PIN check //else if (url.indexOf("/edit") >= 0) subPage = 10; diff --git a/wled00/xml.cpp b/wled00/xml.cpp index de183c5a6..3c7ebd2c3 100755 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -157,8 +157,8 @@ void appendGPIOinfo() { oappend(SET_F(",2")); // DMX hardcoded pin #endif - #ifdef WLED_DEBUG - oappend(SET_F(",")); oappend(itoa(hardwareTX,nS,10));// debug output (TX) pin + #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) + oappend(SET_F(",")); oappend(itoa(hardwareTX,nS,10)); // debug output (TX) pin #endif //Note: Using pin 3 (RX) disables Adalight / Serial JSON @@ -248,23 +248,34 @@ void getSettingsJS(byte subPage, char* dest) if (subPage == SUBPAGE_WIFI) { - sappends('s',SET_F("CS"),clientSSID); - - byte l = strlen(clientPass); - char fpass[l+1]; //fill password field with *** - fpass[l] = 0; - memset(fpass,'*',l); - sappends('s',SET_F("CP"),fpass); - - char k[3]; k[2] = 0; //IP addresses - for (int i = 0; i<4; i++) - { - k[1] = 48+i; //ascii 0,1,2,3 - k[0] = 'I'; sappend('v',k,staticIP[i]); - k[0] = 'G'; sappend('v',k,staticGateway[i]); - k[0] = 'S'; sappend('v',k,staticSubnet[i]); + char nS[10]; + size_t l; + oappend(SET_F("resetWiFi(")); + oappend(itoa(WLED_MAX_WIFI_COUNT,nS,10)); + oappend(SET_F(");")); + for (size_t n = 0; n < multiWiFi.size(); n++) { + l = strlen(multiWiFi[n].clientPass); + char fpass[l+1]; //fill password field with *** + fpass[l] = 0; + memset(fpass,'*',l); + oappend(SET_F("addWiFi(\"")); + oappend(multiWiFi[n].clientSSID); + oappend(SET_F("\",\"")); + oappend(fpass); + oappend(SET_F("\",0x")); + oappend(itoa(multiWiFi[n].staticIP,nS,16)); + oappend(SET_F(",0x")); + oappend(itoa(multiWiFi[n].staticGW,nS,16)); + oappend(SET_F(",0x")); + oappend(itoa(multiWiFi[n].staticSN,nS,16)); + oappend(SET_F(");")); } + sappend('v',SET_F("D0"),dnsAddress[0]); + sappend('v',SET_F("D1"),dnsAddress[1]); + sappend('v',SET_F("D2"),dnsAddress[2]); + sappend('v',SET_F("D3"),dnsAddress[3]); + sappends('s',SET_F("CM"),cmDNS); sappend('i',SET_F("AB"),apBehavior); sappends('s',SET_F("AS"),apSSID); @@ -597,6 +608,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('v',SET_F("OM"),analogClock12pixel); sappend('c',SET_F("OS"),analogClockSecondsTrail); sappend('c',SET_F("O5"),analogClock5MinuteMarks); + sappend('c',SET_F("OB"),analogClockSolidBlack); sappend('c',SET_F("CE"),countdownMode); sappend('v',SET_F("CY"),countdownYear);