├── .changeset
├── mighty-pets-report.md
└── precious-eagle-cactus-fruit.md
├── .clang-format
├── .editorconfig
├── .env
├── .env.development
├── .env.production
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── 10-bug-report.yml
│ ├── 20-feature-request.yml
│ ├── 30-question.yml
│ ├── 40-request-board.yml
│ ├── 70-board-test-report.yml
│ └── config.yml
├── actions
│ ├── build-compilationdb
│ │ └── action.yml
│ ├── build-firmware
│ │ └── action.yml
│ ├── build-frontend
│ │ └── action.yml
│ ├── build-staticfs
│ │ └── action.yml
│ ├── cdn-bump-version
│ │ └── action.yml
│ ├── cdn-prepare
│ │ └── action.yml
│ ├── cdn-upload-firmware
│ │ └── action.yml
│ ├── cdn-upload-version-info
│ │ └── action.yml
│ └── merge-partitions
│ │ └── action.yml
├── dependabot.yml
├── scripts
│ ├── .gitignore
│ ├── get-vars.js
│ ├── package.json
│ └── pnpm-lock.yaml
└── workflows
│ ├── ci-build.yml
│ ├── codeql.yml
│ ├── cpp-linter.yml
│ └── get-vars.yml
├── .gitignore
├── .gitmodules
├── .prettierignore
├── .prettierrc
├── .python-version
├── .vscode
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── RELEASE.md
├── boards
├── Wemos-D1-Mini-ESP32.json
├── Wemos-Lolin-S2-Mini.json
└── Wemos-Lolin-S3.json
├── certificates
├── README.md
├── cacrt_all.pem
├── gen_crt_bundle.py
└── x509_crt_bundle
├── chips
├── ESP32-C3
│ └── 4MB
│ │ └── merge-image.py
├── ESP32-S2
│ └── 4MB
│ │ └── merge-image.py
├── ESP32-S3
│ └── 4MB
│ │ └── merge-image.py
├── ESP32
│ └── 4MB
│ │ └── merge-image.py
├── partitions_4MB.csv
└── partitions_4MB_OTA.csv
├── frontend
├── .eslintignore
├── .gitignore
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── components.json
├── e2e
│ └── demo.test.ts
├── eslint.config.js
├── package.json
├── playwright.config.ts
├── pnpm-lock.yaml
├── src
│ ├── app.css
│ ├── app.d.ts
│ ├── app.html
│ ├── demo.spec.ts
│ ├── lib
│ │ ├── MessageHandlers
│ │ │ ├── WifiNetworkEventHandler.ts
│ │ │ └── index.ts
│ │ ├── Serializers
│ │ │ ├── AccountLinkCommand.ts
│ │ │ ├── SetEstopEnabledCommand.ts
│ │ │ ├── SetEstopPinCommand.ts
│ │ │ ├── SetRfTxPinCommand.ts
│ │ │ ├── WifiNetworkConnectCommand.ts
│ │ │ ├── WifiNetworkDisconnectCommand.ts
│ │ │ ├── WifiNetworkForgetCommand.ts
│ │ │ ├── WifiNetworkSaveCommand.ts
│ │ │ └── WifiScanCommand.ts
│ │ ├── TypeGuards
│ │ │ └── BasicGuards.ts
│ │ ├── WebSocketClient.ts
│ │ ├── _fbs
│ │ │ └── open-shock
│ │ │ │ └── serialization
│ │ │ │ ├── configuration.ts
│ │ │ │ ├── configuration
│ │ │ │ ├── backend-config.ts
│ │ │ │ ├── captive-portal-config.ts
│ │ │ │ ├── estop-config.ts
│ │ │ │ ├── hub-config.ts
│ │ │ │ ├── ota-update-channel.ts
│ │ │ │ ├── ota-update-config.ts
│ │ │ │ ├── ota-update-step.ts
│ │ │ │ ├── rfconfig.ts
│ │ │ │ ├── serial-input-config.ts
│ │ │ │ ├── wi-fi-config.ts
│ │ │ │ └── wi-fi-credentials.ts
│ │ │ │ ├── gateway.ts
│ │ │ │ ├── gateway
│ │ │ │ ├── boot-status.ts
│ │ │ │ ├── gateway-to-hub-message-payload.ts
│ │ │ │ ├── gateway-to-hub-message.ts
│ │ │ │ ├── hub-to-gateway-message-payload.ts
│ │ │ │ ├── hub-to-gateway-message.ts
│ │ │ │ ├── ota-update-failed.ts
│ │ │ │ ├── ota-update-progress.ts
│ │ │ │ ├── ota-update-request.ts
│ │ │ │ ├── ota-update-started.ts
│ │ │ │ ├── ping.ts
│ │ │ │ ├── pong.ts
│ │ │ │ ├── shocker-command-list.ts
│ │ │ │ ├── shocker-command.ts
│ │ │ │ ├── trigger-type.ts
│ │ │ │ └── trigger.ts
│ │ │ │ ├── local.ts
│ │ │ │ ├── local
│ │ │ │ ├── account-link-command-result.ts
│ │ │ │ ├── account-link-command.ts
│ │ │ │ ├── account-link-result-code.ts
│ │ │ │ ├── account-unlink-command.ts
│ │ │ │ ├── error-message.ts
│ │ │ │ ├── hub-to-local-message-payload.ts
│ │ │ │ ├── hub-to-local-message.ts
│ │ │ │ ├── local-to-hub-message-payload.ts
│ │ │ │ ├── local-to-hub-message.ts
│ │ │ │ ├── ota-update-check-for-updates-command.ts
│ │ │ │ ├── ota-update-handle-update-request-command.ts
│ │ │ │ ├── ota-update-set-allow-backend-management-command.ts
│ │ │ │ ├── ota-update-set-check-interval-command.ts
│ │ │ │ ├── ota-update-set-domain-command.ts
│ │ │ │ ├── ota-update-set-is-enabled-command.ts
│ │ │ │ ├── ota-update-set-require-manual-approval-command.ts
│ │ │ │ ├── ota-update-set-update-channel-command.ts
│ │ │ │ ├── ota-update-start-update-command.ts
│ │ │ │ ├── ready-message.ts
│ │ │ │ ├── set-estop-enabled-command-result.ts
│ │ │ │ ├── set-estop-enabled-command.ts
│ │ │ │ ├── set-estop-pin-command-result.ts
│ │ │ │ ├── set-estop-pin-command.ts
│ │ │ │ ├── set-gpioresult-code.ts
│ │ │ │ ├── set-rf-tx-pin-command-result.ts
│ │ │ │ ├── set-rf-tx-pin-command.ts
│ │ │ │ ├── wifi-got-ip-event.ts
│ │ │ │ ├── wifi-lost-ip-event.ts
│ │ │ │ ├── wifi-network-connect-command.ts
│ │ │ │ ├── wifi-network-disconnect-command.ts
│ │ │ │ ├── wifi-network-event.ts
│ │ │ │ ├── wifi-network-forget-command.ts
│ │ │ │ ├── wifi-network-save-command.ts
│ │ │ │ ├── wifi-scan-command.ts
│ │ │ │ └── wifi-scan-status-message.ts
│ │ │ │ ├── types.ts
│ │ │ │ └── types
│ │ │ │ ├── firmware-boot-type.ts
│ │ │ │ ├── ota-update-progress-task.ts
│ │ │ │ ├── sem-ver.ts
│ │ │ │ ├── shocker-command-type.ts
│ │ │ │ ├── shocker-model-type.ts
│ │ │ │ ├── wifi-auth-mode.ts
│ │ │ │ ├── wifi-network-event-type.ts
│ │ │ │ ├── wifi-network.ts
│ │ │ │ └── wifi-scan-status.ts
│ │ ├── components
│ │ │ ├── AbsolutelySureButton.svelte
│ │ │ ├── GpioPinSelector.svelte
│ │ │ ├── Layout
│ │ │ │ ├── Footer.svelte
│ │ │ │ └── Header.svelte
│ │ │ ├── LightSwitch.svelte
│ │ │ ├── WiFiDetailsDialog.svelte
│ │ │ ├── WiFiList.svelte
│ │ │ └── ui
│ │ │ │ ├── button
│ │ │ │ ├── button.svelte
│ │ │ │ └── index.ts
│ │ │ │ ├── dialog
│ │ │ │ ├── dialog-content.svelte
│ │ │ │ ├── dialog-description.svelte
│ │ │ │ ├── dialog-footer.svelte
│ │ │ │ ├── dialog-header.svelte
│ │ │ │ ├── dialog-overlay.svelte
│ │ │ │ ├── dialog-title.svelte
│ │ │ │ └── index.ts
│ │ │ │ ├── dropdown-menu
│ │ │ │ ├── dropdown-menu-checkbox-item.svelte
│ │ │ │ ├── dropdown-menu-content.svelte
│ │ │ │ ├── dropdown-menu-group-heading.svelte
│ │ │ │ ├── dropdown-menu-item.svelte
│ │ │ │ ├── dropdown-menu-label.svelte
│ │ │ │ ├── dropdown-menu-radio-item.svelte
│ │ │ │ ├── dropdown-menu-separator.svelte
│ │ │ │ ├── dropdown-menu-shortcut.svelte
│ │ │ │ ├── dropdown-menu-sub-content.svelte
│ │ │ │ ├── dropdown-menu-sub-trigger.svelte
│ │ │ │ └── index.ts
│ │ │ │ ├── input
│ │ │ │ ├── index.ts
│ │ │ │ └── input.svelte
│ │ │ │ ├── label
│ │ │ │ ├── index.ts
│ │ │ │ └── label.svelte
│ │ │ │ ├── scroll-area
│ │ │ │ ├── index.ts
│ │ │ │ ├── scroll-area-scrollbar.svelte
│ │ │ │ └── scroll-area.svelte
│ │ │ │ └── sonner
│ │ │ │ ├── index.ts
│ │ │ │ └── sonner.svelte
│ │ ├── index.ts
│ │ ├── mappers
│ │ │ └── ConfigMapper.ts
│ │ ├── stores
│ │ │ ├── ColorSchemeStore.ts
│ │ │ ├── HubStateStore.ts
│ │ │ ├── UsedPinsStore.ts
│ │ │ └── index.ts
│ │ ├── types
│ │ │ ├── HubState.ts
│ │ │ ├── WiFiNetwork.ts
│ │ │ ├── WiFiNetworkGroup.ts
│ │ │ └── index.ts
│ │ └── utils.ts
│ └── routes
│ │ ├── +layout.svelte
│ │ ├── +layout.ts
│ │ └── +page.svelte
├── static
│ ├── favicon.ico
│ └── logo.svg
├── svelte.config.js
├── tailwind.config.ts
├── tsconfig.json
└── vite.config.ts
├── include
├── AccountLinkResultCode.h
├── CaptivePortal.h
├── CaptivePortalInstance.h
├── Checksum.h
├── Chipset.h
├── CommandHandler.h
├── Common.h
├── Convert.h
├── Core.h
├── FirmwareBootType.h
├── FormatHelpers.h
├── GatewayClient.h
├── GatewayClientState.h
├── GatewayConnectionManager.h
├── Hashing.h
├── Logging.h
├── OtaUpdateChannel.h
├── OtaUpdateManager.h
├── OtaUpdateStep.h
├── PinPatternManager.h
├── RGBPatternManager.h
├── RateLimiter.h
├── ReadWriteMutex.h
├── SemVer.h
├── SetGPIOResultCode.h
├── ShockerCommandType.h
├── ShockerModelType.h
├── SimpleMutex.h
├── VisualStateManager.h
├── WebSocketDeFragger.h
├── WebSocketMessageType.h
├── config
│ ├── BackendConfig.h
│ ├── CaptivePortalConfig.h
│ ├── Config.h
│ ├── ConfigBase.h
│ ├── EStopConfig.h
│ ├── OtaUpdateConfig.h
│ ├── RFConfig.h
│ ├── RootConfig.h
│ ├── SerialInputConfig.h
│ ├── WiFiConfig.h
│ ├── WiFiCredentials.h
│ └── internal
│ │ └── utils.h
├── estop
│ ├── EStopManager.h
│ └── EStopState.h
├── events
│ └── Events.h
├── http
│ ├── HTTPRequestManager.h
│ └── JsonAPI.h
├── message_handlers
│ ├── WebSocket.h
│ └── impl
│ │ ├── WSGateway.h
│ │ └── WSLocal.h
├── radio
│ ├── RFTransmitter.h
│ └── rmt
│ │ ├── CaiXianlinEncoder.h
│ │ ├── MainEncoder.h
│ │ ├── Petrainer998DREncoder.h
│ │ ├── PetrainerEncoder.h
│ │ ├── T330Encoder.h
│ │ └── internal
│ │ └── Shared.h
├── serial
│ ├── SerialInputHandler.h
│ └── command_handlers
│ │ ├── CommandEntry.h
│ │ ├── common.h
│ │ └── index.h
├── serialization
│ ├── CallbackFn.h
│ ├── JsonAPI.h
│ ├── JsonSerial.h
│ ├── WSGateway.h
│ ├── WSLocal.h
│ └── _fbs
│ │ ├── FirmwareBootType_generated.h
│ │ ├── GatewayToHubMessage_generated.h
│ │ ├── HubConfig_generated.h
│ │ ├── HubToGatewayMessage_generated.h
│ │ ├── HubToLocalMessage_generated.h
│ │ ├── LocalToHubMessage_generated.h
│ │ ├── OtaUpdateProgressTask_generated.h
│ │ ├── SemVer_generated.h
│ │ ├── ShockerCommandType_generated.h
│ │ ├── ShockerModelType_generated.h
│ │ ├── WifiAuthMode_generated.h
│ │ ├── WifiNetworkEventType_generated.h
│ │ ├── WifiNetwork_generated.h
│ │ └── WifiScanStatus_generated.h
├── span.h
├── util
│ ├── Base64Utils.h
│ ├── CertificateUtils.h
│ ├── DigitCounter.h
│ ├── FnProxy.h
│ ├── HexUtils.h
│ ├── IPAddressUtils.h
│ ├── PartitionUtils.h
│ ├── StringUtils.h
│ └── TaskUtils.h
└── wifi
│ ├── WiFiManager.h
│ ├── WiFiNetwork.h
│ ├── WiFiScanManager.h
│ └── WiFiScanStatus.h
├── lib
└── README
├── platformio.ini
├── requirements.txt
├── scripts
├── .gitignore
├── build_frontend.py
├── embed_env_vars.py
├── fetch_flatc.py
├── flatc
├── flatc.exe
├── generate_schemas.py
├── install_dependencies.py
├── merge_image.py
├── use_openshock_params.py
└── utils
│ ├── __init__.py
│ ├── boardconf.py
│ ├── conv.py
│ ├── dotenv.py
│ ├── pioenv.py
│ ├── shorthands.py
│ └── sysenv.py
├── src
├── CaptivePortal.cpp
├── CaptivePortalInstance.cpp
├── CommandHandler.cpp
├── CompatibilityChecks.cpp
├── Convert.cpp
├── EStopManager.cpp
├── GatewayClient.cpp
├── GatewayConnectionManager.cpp
├── OtaUpdateManager.cpp
├── PinPatternManager.cpp
├── RGBPatternManager.cpp
├── RateLimiter.cpp
├── ReadWriteMutex.cpp
├── SemVer.cpp
├── SimpleMutex.cpp
├── VisualStateManager.cpp
├── WebSocketDeFragger.cpp
├── config
│ ├── BackendConfig.cpp
│ ├── CaptivePortalConfig.cpp
│ ├── Config.cpp
│ ├── EStopConfig.cpp
│ ├── OtaUpdateConfig.cpp
│ ├── RFConfig.cpp
│ ├── RootConfig.cpp
│ ├── SerialInputConfig.cpp
│ ├── WiFiConfig.cpp
│ ├── WiFiCredentials.cpp
│ └── internal
│ │ └── utils.cpp
├── events
│ └── Events.cpp
├── http
│ ├── HTTPRequestManager.cpp
│ └── JsonAPI.cpp
├── main.cpp
├── message_handlers
│ └── websocket
│ │ ├── Gateway.cpp
│ │ ├── Local.cpp
│ │ ├── gateway
│ │ ├── OtaUpdateRequest.cpp
│ │ ├── Ping.cpp
│ │ ├── ShockerCommandList.cpp
│ │ ├── Trigger.cpp
│ │ └── _InvalidMessage.cpp
│ │ └── local
│ │ ├── AccountLinkCommand.cpp
│ │ ├── AccountUnlinkCommand.cpp
│ │ ├── OtaUpdateCheckForUpdatesCommand.cpp
│ │ ├── OtaUpdateHandleUpdateRequestCommand.cpp
│ │ ├── OtaUpdateSetAllowBackendManagementCommand.cpp
│ │ ├── OtaUpdateSetCheckIntervalCommand.cpp
│ │ ├── OtaUpdateSetDomainCommand.cpp
│ │ ├── OtaUpdateSetIsEnabledCommand.cpp
│ │ ├── OtaUpdateSetRequireManualApprovalCommand.cpp
│ │ ├── OtaUpdateSetUpdateChannelCommand.cpp
│ │ ├── OtaUpdateStartUpdateCommand.cpp
│ │ ├── SetEStopEnabledCommand.cpp
│ │ ├── SetEStopPinCommand.cpp
│ │ ├── SetRfTxPinCommand.cpp
│ │ ├── WiFiNetworkConnectCommand.cpp
│ │ ├── WiFiNetworkDisconnectCommand.cpp
│ │ ├── WiFiNetworkForgetCommand.cpp
│ │ ├── WiFiNetworkSaveCommand.cpp
│ │ ├── WiFiScanCommand.cpp
│ │ └── _InvalidMessage.cpp
├── radio
│ ├── RFTransmitter.cpp
│ └── rmt
│ │ ├── CaiXianlinEncoder.cpp
│ │ ├── MainEncoder.cpp
│ │ ├── Petrainer998DREncoder.cpp
│ │ ├── PetrainerEncoder.cpp
│ │ └── T330Encoder.cpp
├── serial
│ ├── SerialInputHandler.cpp
│ └── command_handlers
│ │ ├── CommandEntry.cpp
│ │ ├── authtoken.cpp
│ │ ├── domain.cpp
│ │ ├── echo.cpp
│ │ ├── estop.cpp
│ │ ├── factoryreset.cpp
│ │ ├── hostname.cpp
│ │ ├── jsonconfig.cpp
│ │ ├── keepalive.cpp
│ │ ├── networks.cpp
│ │ ├── rawconfig.cpp
│ │ ├── restart.cpp
│ │ ├── rftransmit.cpp
│ │ ├── rftxpin.cpp
│ │ ├── sysinfo.cpp
│ │ ├── validgpios.cpp
│ │ └── version.cpp
├── serialization
│ ├── JsonAPI.cpp
│ ├── JsonSerial.cpp
│ ├── WSGateway.cpp
│ └── WSLocal.cpp
├── util
│ ├── Base64Utils.cpp
│ ├── CertificateUtils.cpp
│ ├── DigitCounter.cpp
│ ├── IPAddressUtils.cpp
│ ├── ParitionUtils.cpp
│ ├── StringUtils.cpp
│ └── TaskUtils.cpp
└── wifi
│ ├── WiFiManager.cpp
│ ├── WiFiNetwork.cpp
│ └── WiFiScanManager.cpp
└── test
└── README
/.changeset/mighty-pets-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | 'frontend': patch
3 | ---
4 |
5 | Improve authtoken handling in 401 responses
6 |
--------------------------------------------------------------------------------
/.changeset/precious-eagle-cactus-fruit.md:
--------------------------------------------------------------------------------
1 | ---
2 | 'firmware': patch
3 | ---
4 |
5 | fix: Serial now uses CRLF rather than just LF for better compatibility
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor config
2 |
3 | [*]
4 |
5 | # Indentation
6 | indent_style = space
7 | indent_size = 2
8 |
9 | # Line endings
10 | end_of_line = lf
11 | insert_final_newline = true
12 | trim_trailing_whitespace = true
13 |
14 | [*.py]
15 | indent_size = 4
16 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | OPENSHOCK_API_DOMAIN=api.openshock.app
2 | OPENSHOCK_FW_CDN_DOMAIN=firmware.openshock.org
3 | OPENSHOCK_FW_HOSTNAME=OpenShock
4 | OPENSHOCK_FW_AP_PREFIX=OpenShock-
5 | OPENSHOCK_URI_BUFFER_SIZE=256
6 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | # Included by frontend/ (DO NOT RENAME THIS FILE!)
2 | # Intended for development builds (locally).
3 | LOG_LEVEL=VERBOSE
4 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | # Included by frontend/ (DO NOT RENAME THIS FILE!)
2 | # Intended for all CI firmware builds.
3 | LOG_LEVEL=INFO
4 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 | *.txt text eol=lf
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/20-feature-request.yml:
--------------------------------------------------------------------------------
1 | name: 'Feature Request'
2 | description: "Is there a feature you'd really like to see? Request it here."
3 | title: '[Feature] '
4 | labels: ['type: enhancement']
5 | projects: ['OpenShock/3']
6 |
7 | body:
8 |
9 | - type: markdown
10 | attributes:
11 | value: |
12 | # Checklist
13 |
14 | - type: checkboxes
15 | id: checklist
16 | attributes:
17 | label: Pre-submission checklist
18 | description: |
19 | To prevent wasting your or our time, please fill out the below checklist before continuing.
20 | Thanks for understanding!
21 | options:
22 | - label: 'I checked that there is no other Feature Request describing my wish.'
23 | required: true
24 | - label: 'I checked that this feature is, in fact, not supported.'
25 | required: true
26 | - label: 'I accept that this issue may be closed if any of the above are found to be untrue.'
27 | required: true
28 |
29 | - type: markdown
30 | attributes:
31 | value: |
32 | # Describe the feature
33 |
34 | - type: textarea
35 | id: feature-request
36 | attributes:
37 | label: 'What should be possible that currently is not?'
38 | validations:
39 | required: true
40 |
41 | - type: markdown
42 | attributes:
43 | value: |
44 | # Anything else?
45 |
46 | - type: textarea
47 | id: anything-else
48 | attributes:
49 | label: 'Other remarks'
50 | validations:
51 | required: false
52 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/30-question.yml:
--------------------------------------------------------------------------------
1 | name: 'Question'
2 | description: "Can't figure something out? Feel free to ask."
3 | title: '[Question] '
4 | labels: ['type: question']
5 | projects: ['OpenShock/3']
6 |
7 | body:
8 |
9 | - type: markdown
10 | attributes:
11 | value: |
12 | # Question
13 |
14 | - type: textarea
15 | id: question
16 | attributes:
17 | label: 'Ask your question!'
18 | placeholder: |
19 | How do I..?
20 | Is it possible to..?
21 | Are you planning to..?
22 | validations:
23 | required: true
24 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 |
--------------------------------------------------------------------------------
/.github/actions/build-compilationdb/action.yml:
--------------------------------------------------------------------------------
1 | name: build-compilationdb
2 | description: Builds the compilation database for the firmware for code analysis
3 | inputs:
4 | version:
5 | required: true
6 | description: 'Current firmware version'
7 | skip-checkout:
8 | description: 'If true, skips checkout'
9 | required: false
10 | default: false
11 |
12 | runs:
13 | using: composite
14 | steps:
15 | - uses: actions/checkout@v4
16 | if: ${{ !inputs.skip-checkout }}
17 |
18 | - uses: actions/cache@v4
19 | with:
20 | path: |
21 | ~/.platformio/platforms
22 | ~/.platformio/packages
23 | ~/.platformio/.cache
24 | key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini', 'requirements.txt') }}
25 |
26 | - uses: actions/setup-python@v5
27 | with:
28 | cache: 'pip'
29 |
30 | - name: Install python dependencies
31 | shell: bash
32 | run: pip install -r requirements.txt
33 |
34 | - name: Build firmware
35 | working-directory: .
36 | shell: bash
37 | run: pio run -e ci-build -t compiledb
38 | env:
39 | OPENSHOCK_FW_VERSION: ${{ inputs.version }}
40 | OPENSHOCK_FW_GIT_REF: ${{ github.ref }}
41 | OPENSHOCK_FW_GIT_COMMIT: ${{ github.sha }}
42 | OPENSHOCK_FW_BUILD_DATE: ${{ github.event.head_commit.timestamp }}
--------------------------------------------------------------------------------
/.github/actions/build-firmware/action.yml:
--------------------------------------------------------------------------------
1 | name: build-firmware
2 | description: Builds the firmware partitions and uploads them as an artifact
3 | inputs:
4 | board:
5 | required: true
6 | description: 'Board name to build'
7 | version:
8 | required: true
9 | description: 'Current firmware version'
10 | skip-checkout:
11 | description: 'If true, skips checkout'
12 | required: false
13 | default: false
14 |
15 | runs:
16 | using: composite
17 | steps:
18 | - uses: actions/checkout@v4
19 | if: ${{ !inputs.skip-checkout }}
20 |
21 | - uses: actions/cache@v4
22 | with:
23 | path: |
24 | ~/.platformio/platforms
25 | ~/.platformio/packages
26 | ~/.platformio/.cache
27 | key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini', 'requirements.txt') }}
28 |
29 | - uses: actions/setup-python@v5
30 | with:
31 | cache: 'pip'
32 |
33 | - name: Install python dependencies
34 | shell: bash
35 | run: pip install -r requirements.txt
36 |
37 | - name: Build firmware
38 | working-directory: .
39 | shell: bash
40 | run: pio run -e ${{ inputs.board }}
41 | env:
42 | OPENSHOCK_FW_VERSION: ${{ inputs.version }}
43 | OPENSHOCK_FW_GIT_REF: ${{ github.ref }}
44 | OPENSHOCK_FW_GIT_COMMIT: ${{ github.sha }}
45 | OPENSHOCK_FW_BUILD_DATE: ${{ github.event.head_commit.timestamp }}
46 |
47 | - name: Upload build artifacts
48 | uses: actions/upload-artifact@v4
49 | with:
50 | name: firmware_build_${{ inputs.board }}
51 | path: .pio/build/${{ inputs.board }}/*.bin
52 | retention-days: 1
53 | if-no-files-found: error
54 |
--------------------------------------------------------------------------------
/.github/actions/build-staticfs/action.yml:
--------------------------------------------------------------------------------
1 | name: build-staticfs
2 | description: Builds the static filesystem partition and uploads it as an artifact
3 | inputs:
4 | version:
5 | required: true
6 | description: 'Current firmware version'
7 | skip-checkout:
8 | description: 'If true, skips checkout'
9 | required: false
10 | default: false
11 |
12 | runs:
13 | using: composite
14 | steps:
15 | - uses: actions/checkout@v4
16 | if: ${{ !inputs.skip-checkout }}
17 |
18 | - uses: actions/cache@v4
19 | with:
20 | path: |
21 | ~/.platformio/platforms
22 | ~/.platformio/packages
23 | ~/.platformio/.cache
24 | key: pio-${{ runner.os }}-${{ hashFiles('platformio.ini', 'requirements.txt') }}
25 |
26 | - uses: actions/setup-python@v5
27 | with:
28 | cache: 'pip'
29 |
30 | - name: Install dependencies
31 | shell: bash
32 | run: pip install -r requirements.txt
33 |
34 | - name: Download built frontend
35 | uses: actions/download-artifact@v4
36 | with:
37 | name: frontend
38 | path: frontend/build/
39 |
40 | - name: Build filesystem partition
41 | shell: bash
42 | run: pio run --target buildfs -e fs
43 | env:
44 | OPENSHOCK_FW_VERSION: ${{ inputs.version }}
45 | OPENSHOCK_FW_GIT_REF: ${{ github.ref }}
46 | OPENSHOCK_FW_GIT_COMMIT: ${{ github.sha }}
47 | OPENSHOCK_FW_BUILD_DATE: ${{ github.event.head_commit.timestamp }}
48 |
49 | - name: Rename partition binary
50 | shell: bash
51 | run: mv .pio/build/fs/littlefs.bin staticfs.bin
52 |
53 | - name: Upload internal filesystem artifact
54 | uses: actions/upload-artifact@v4
55 | with:
56 | name: firmware_staticfs
57 | path: staticfs.bin
58 | retention-days: 1
59 | if-no-files-found: error
60 |
--------------------------------------------------------------------------------
/.github/actions/cdn-bump-version/action.yml:
--------------------------------------------------------------------------------
1 | name: cdn-bump-version
2 | description: Uploads version file to CDN
3 | inputs:
4 | bunny-stor-hostname:
5 | description: Bunny SFTP Hostname
6 | required: true
7 | bunny-stor-username:
8 | description: Bunny SFTP Username
9 | required: true
10 | bunny-stor-password:
11 | description: Bunny SFTP Password
12 | required: true
13 | bunny-api-key:
14 | description: Bunny API key
15 | required: true
16 | bunny-cdn-url:
17 | description: Bunny pull zone base url e.g. https://firmware.openshock.org (no trailing slash)
18 | required: true
19 | version:
20 | description: 'Version of the release'
21 | required: true
22 | release-channel:
23 | description: 'Release channel that describes this upload'
24 | required: true
25 |
26 | runs:
27 | using: composite
28 | steps:
29 | - name: Prepare Upload Folder
30 | shell: bash
31 | run: |
32 | mkdir -p upload
33 | echo "${{ inputs.version }}" >> upload/version-${{ inputs.release-channel }}.txt
34 |
35 | - name: Upload version file
36 | uses: milanmk/actions-file-deployer@master
37 | with:
38 | remote-protocol: "sftp"
39 | remote-host: "${{ inputs.bunny-stor-hostname }}"
40 | remote-user: "${{ inputs.bunny-stor-username }}"
41 | remote-password: "${{ inputs.bunny-stor-password }}"
42 | remote-path: "/"
43 | local-path: "upload"
44 | sync: "full"
45 |
46 | - name: Purge CDN cache
47 | shell: bash
48 | run: |
49 | curl -X POST "https://api.bunny.net/purge?url=${{ inputs.bunny-cdn-url }}/version-${{ inputs.release-channel }}.txt" \
50 | -H "Content-Type: application/json" \
51 | -H "AccessKey: ${{ inputs.bunny-api-key }}"
--------------------------------------------------------------------------------
/.github/actions/cdn-prepare/action.yml:
--------------------------------------------------------------------------------
1 | name: cdn-prepare
2 | description: Bunny sshpass and knowhosts setup
3 | inputs:
4 | bunny-ssh-knownhosts:
5 | description: Bunny SFTP Hostname
6 | required: true
7 |
8 | runs:
9 | using: composite
10 | steps:
11 | - name: Install sshpass
12 | shell: bash
13 | run: sudo apt-get install -y sshpass
14 |
15 | - name: Configure known hosts
16 | shell: bash
17 | run: |
18 | mkdir -p ~/.ssh
19 | echo "${{ inputs.bunny-ssh-knownhosts }}" >> ~/.ssh/known_hosts
20 |
21 |
--------------------------------------------------------------------------------
/.github/actions/cdn-upload-version-info/action.yml:
--------------------------------------------------------------------------------
1 | name: cdn-upload-version-info
2 | description: Uploads version specific info to CDN
3 | inputs:
4 | bunny-stor-hostname:
5 | description: Bunny SFTP Hostname
6 | required: true
7 | bunny-stor-username:
8 | description: Bunny SFTP Username
9 | required: true
10 | bunny-stor-password:
11 | description: Bunny SFTP Password
12 | required: true
13 | fw-version:
14 | description: Firmware version
15 | required: true
16 | release-channel:
17 | description: 'Release channel that describes this upload'
18 | required: true
19 | boards:
20 | description: 'List of boards, separated by newlines'
21 | required: true
22 |
23 | runs:
24 | using: composite
25 | steps:
26 |
27 | - name: Prepare Upload Folder
28 | shell: bash
29 | run: |
30 | rm -rf upload/
31 | mkdir -p upload/
32 |
33 | - name: Create boards.txt
34 | shell: bash
35 | run: |
36 | echo -e '${{ inputs.boards }}' >> upload/boards.txt
37 |
38 | - name: Upload artifacts to CDN
39 | uses: milanmk/actions-file-deployer@master
40 | with:
41 | remote-protocol: "sftp"
42 | remote-host: "${{ inputs.bunny-stor-hostname }}"
43 | remote-user: "${{ inputs.bunny-stor-username }}"
44 | remote-password: "${{ inputs.bunny-stor-password }}"
45 | remote-path: "/${{ inputs.fw-version }}/"
46 | local-path: "upload"
47 | sync: "full"
--------------------------------------------------------------------------------
/.github/actions/merge-partitions/action.yml:
--------------------------------------------------------------------------------
1 | name: merge-partitions
2 | description: Merges multiple partitions into a single flashable binary
3 | inputs:
4 | version:
5 | description: 'Version of the firmware'
6 | required: true
7 | board:
8 | description: 'Board name to merge partitions for'
9 | required: true
10 | skip-checkout:
11 | description: 'If true, skips checkout'
12 | required: false
13 | default: false
14 |
15 | runs:
16 | using: composite
17 | steps:
18 | - uses: actions/checkout@v4
19 | if: ${{ !inputs.skip-checkout }}
20 | with:
21 | sparse-checkout: |
22 | scripts
23 | boards
24 | chips
25 |
26 | - uses: actions/setup-python@v5
27 | with:
28 | cache: 'pip'
29 |
30 | - name: Install dependencies
31 | shell: bash
32 | run: pip install -r requirements.txt
33 |
34 | - name: Download static filesystem partition
35 | uses: actions/download-artifact@v4
36 | with:
37 | name: firmware_staticfs
38 |
39 | - name: Download firmware partitions
40 | uses: actions/download-artifact@v4
41 | with:
42 | name: firmware_build_${{ inputs.board }}
43 |
44 | - name: Merge partitions
45 | shell: bash
46 | run: |
47 | python scripts/merge_image.py ${{ inputs.board }}
48 | mv merged.bin OpenShock_${{ inputs.board }}_${{ inputs.version }}.bin
49 |
50 | - name: Upload merged firmware binary
51 | uses: actions/upload-artifact@v4
52 | with:
53 | name: firmware_merged_${{ inputs.board }}
54 | path: OpenShock_${{ inputs.board }}_*.bin
55 | retention-days: 7
56 | if-no-files-found: error
57 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | # Daily checks for updates in Github Actions (CI/CD workflows)
9 | - package-ecosystem: 'github-actions'
10 | directory: '/'
11 | schedule:
12 | interval: 'weekly'
13 | day: 'monday'
14 | time: '06:00'
15 | groups:
16 | ci-cd:
17 | patterns:
18 | - '*' # Group all updates together
19 |
20 | # Daily checks for npm package updates in CI-CD scripts
21 | - package-ecosystem: 'npm'
22 | directory: '/.github/scripts'
23 | schedule:
24 | interval: 'weekly'
25 | day: 'monday'
26 | time: '06:00'
27 | groups:
28 | ci-cd:
29 | patterns:
30 | - '*' # Group all updates together
31 |
32 | # Daily checks for pip package updates in build system scripts
33 | - package-ecosystem: 'pip'
34 | directory: '/'
35 | schedule:
36 | interval: 'weekly'
37 | day: 'monday'
38 | time: '06:00'
39 | groups:
40 | build-system:
41 | patterns:
42 | - '*' # Group all updates together
43 |
44 | # Daily checks for npm package updates in frontend
45 | - package-ecosystem: 'npm'
46 | directory: '/frontend'
47 | schedule:
48 | interval: 'weekly'
49 | day: 'monday'
50 | time: '06:00'
51 | groups:
52 | frontend:
53 | patterns:
54 | - '*' # Group all updates together
55 |
--------------------------------------------------------------------------------
/.github/scripts/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.github/scripts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "get-variables",
3 | "version": "1.0.0",
4 | "private": true,
5 | "type": "module",
6 | "main": "src/index.ts",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "dependencies": {
11 | "@actions/core": "^1.10.1",
12 | "@actions/github": "^6.0.1",
13 | "ini": "^5.0.0",
14 | "semver": "^7.7.2"
15 | },
16 | "engines": {
17 | "node": "^22.14.0",
18 | "pnpm": "^10.6.4"
19 | },
20 | "volta": {
21 | "node": "22.14.0"
22 | },
23 | "packageManager": "pnpm@10.6.4"
24 | }
25 |
--------------------------------------------------------------------------------
/.github/workflows/cpp-linter.yml:
--------------------------------------------------------------------------------
1 | name: cpp-linter
2 |
3 | on:
4 | pull_request:
5 | types: [opened, reopened, synchronize]
6 | paths: ['**.c', '**.h', '**.cpp', '**.hpp', '.clang-format']
7 | push:
8 | paths: ['**.c', '**.h', '**.cpp', '**.hpp', '.clang-format']
9 | workflow_dispatch: # Manually invoked by user.
10 |
11 | jobs:
12 | get-vars:
13 | uses: ./.github/workflows/get-vars.yml
14 |
15 | cpp-linter:
16 | name: C/C++ Linter
17 | runs-on: ubuntu-latest
18 | needs: get-vars
19 |
20 | permissions:
21 | contents: write
22 | pull-requests: write
23 |
24 | steps:
25 | - name: Checkout repository
26 | uses: actions/checkout@v4
27 |
28 | - uses: ./.github/actions/build-compilationdb
29 | with:
30 | version: 0.0.0-test+build # Doesn't matter, just need the compilation database
31 | skip-checkout: true
32 |
33 | - uses: cpp-linter/cpp-linter-action@v2
34 | id: linter
35 | env:
36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37 | with:
38 | style: file
39 | version: 18
40 | lines-changed-only: diff
41 | thread-comments: true
42 | file-annotations: false
43 |
44 | - name: Fail fast?!
45 | if: steps.linter.outputs.checks-failed > 0
46 | run: |
47 | echo "Some files failed the linting checks!"
48 | # for actual deployment
49 | # run: exit 1
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/extensions.json
5 | .vscode/launch.json
6 | .vscode/ipch
7 | *.bin
8 |
9 | # data/www is autogenerated by the build process, ignore it:
10 | data/www
11 | !data/**/*.bin
12 |
13 | # ignore local config files
14 | *.local
15 |
16 | # ignore generated files
17 | .vs
18 | packages
19 | *.sln
20 | compile_commands.json
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "schemas"]
2 | path = schemas
3 | url = https://github.com/OpenShock/flatbuffers-schemas
4 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/.DS_Store
2 | **/node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | **/.env
7 | **/.env.*
8 |
9 | # Ignore files for PNPM, NPM and YARN
10 | **/pnpm-lock.yaml
11 | **/package-lock.json
12 | **/yarn.lock
13 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "semi": true,
4 | "useTabs": false,
5 | "singleQuote": true,
6 | "trailingComma": "es5",
7 | "printWidth": 256
8 | }
9 |
--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------
1 | 3.12.5
2 |
--------------------------------------------------------------------------------
/RELEASE.md:
--------------------------------------------------------------------------------
1 | ## Flashing the firmware
2 |
3 | Download `OpenShock_[board]_[version].bin` and flash it to your microcontroller:
4 |
5 | ```bash
6 | esptool write_flash 0x0 OpenShock_[board]_[version].bin
7 | ```
8 |
--------------------------------------------------------------------------------
/boards/Wemos-D1-Mini-ESP32.json:
--------------------------------------------------------------------------------
1 | {
2 | "build": {
3 | "arduino": {
4 | "ldscript": "esp32_out.ld"
5 | },
6 | "core": "esp32",
7 | "extra_flags": "-DARDUINO_D1_MINI32",
8 | "f_cpu": "240000000L",
9 | "f_flash": "40000000L",
10 | "flash_mode": "dio",
11 | "mcu": "esp32",
12 | "variant": "d1_mini32"
13 | },
14 | "connectivity": [
15 | "wifi",
16 | "bluetooth",
17 | "ethernet",
18 | "can"
19 | ],
20 | "debug": {
21 | "openocd_board": "esp-wroom-32.cfg"
22 | },
23 | "frameworks": [
24 | "arduino",
25 | "espidf"
26 | ],
27 | "name": "WEMOS D1 MINI ESP32",
28 | "upload": {
29 | "flash_size": "4MB",
30 | "maximum_ram_size": 327680,
31 | "maximum_size": 4194304,
32 | "require_upload_port": true,
33 | "speed": 460800
34 | },
35 | "url": "https://www.wemos.cc",
36 | "vendor": "WEMOS"
37 | }
--------------------------------------------------------------------------------
/boards/Wemos-Lolin-S2-Mini.json:
--------------------------------------------------------------------------------
1 | {
2 | "build": {
3 | "arduino": {
4 | "ldscript": "esp32s2_out.ld"
5 | },
6 | "core": "esp32",
7 | "extra_flags": [
8 | "-DARDUINO_LOLIN_S2_MINI",
9 | "-DBOARD_HAS_PSRAM",
10 | "-DARDUINO_USB_CDC_ON_BOOT=1"
11 | ],
12 | "f_cpu": "240000000L",
13 | "f_flash": "80000000L",
14 | "flash_mode": "dio",
15 | "hwids": [
16 | [
17 | "0X303A",
18 | "0x80C2"
19 | ]
20 | ],
21 | "mcu": "esp32s2",
22 | "variant": "lolin_s2_mini"
23 | },
24 | "connectivity": [
25 | "wifi"
26 | ],
27 | "debug": {
28 | "openocd_target": "esp32s2.cfg"
29 | },
30 | "frameworks": [
31 | "arduino",
32 | "espidf"
33 | ],
34 | "name": "WEMOS LOLIN S2 Mini",
35 | "upload": {
36 | "flash_size": "4MB",
37 | "maximum_ram_size": 327680,
38 | "maximum_size": 4194304,
39 | "use_1200bps_touch": true,
40 | "wait_for_upload_port": true,
41 | "require_upload_port": true,
42 | "speed": 921600
43 | },
44 | "url": "https://www.wemos.cc/en/latest/s2/s2_mini.html",
45 | "vendor": "WEMOS"
46 | }
--------------------------------------------------------------------------------
/boards/Wemos-Lolin-S3.json:
--------------------------------------------------------------------------------
1 | {
2 | "build": {
3 | "arduino": {
4 | "ldscript": "esp32s3_out.ld",
5 | "partitions": "default_16MB.csv",
6 | "memory_type": "qio_opi"
7 | },
8 | "core": "esp32",
9 | "extra_flags": ["-DBOARD_HAS_PSRAM", "-DARDUINO_LOLIN_S3", "-DARDUINO_USB_MODE=1"],
10 | "f_cpu": "240000000L",
11 | "f_flash": "80000000L",
12 | "flash_mode": "qio",
13 | "hwids": [["0x303A", "0x1001"]],
14 | "mcu": "esp32s3",
15 | "variant": "lolin_s3"
16 | },
17 | "connectivity": ["wifi", "bluetooth"],
18 | "debug": {
19 | "openocd_target": "esp32s3.cfg"
20 | },
21 | "frameworks": ["arduino", "espidf"],
22 | "name": "WEMOS LOLIN S3",
23 | "upload": {
24 | "flash_size": "16MB",
25 | "maximum_ram_size": 327680,
26 | "maximum_size": 16777216,
27 | "use_1200bps_touch": true,
28 | "wait_for_upload_port": true,
29 | "require_upload_port": true,
30 | "speed": 460800
31 | },
32 | "url": "https://www.wemos.cc/en/latest/s3/index.html",
33 | "vendor": "WEMOS"
34 | }
35 |
--------------------------------------------------------------------------------
/certificates/README.md:
--------------------------------------------------------------------------------
1 | # Certificates used for HTTPS
2 |
3 | These certificates are fetched from [CURL's website](https://curl.se/docs/caextract.html) and are used for HTTPS connections.
4 |
5 | ## How to update
6 |
7 | 1. Download the latest version of the certificate bundle along with its sha256 from [CURL's website](https://curl.se/docs/caextract.html).
8 | 2. Replace the `cacrt_all.pem` file in this directory with the new one.
9 | 3. Run `gen_crt_bundle.py` to generate the new `x509_crt_bundle` file.
10 | 4. Commit the changes.
11 |
12 | ## References
13 |
14 | - [CURL's website](https://curl.se/docs/caextract.html)
15 | - [Espressif's documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_crt_bundle.html)
16 | - [WiFiClientSecure Documentation](https://github.com/espressif/arduino-esp32/tree/master/libraries/WiFiClientSecure#using-a-bundle-of-root-certificate-authority-certificates)
17 |
--------------------------------------------------------------------------------
/certificates/x509_crt_bundle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenShock/Firmware/70dd3619e14ff939025a137e5db1defdd00131bc/certificates/x509_crt_bundle
--------------------------------------------------------------------------------
/chips/ESP32-C3/4MB/merge-image.py:
--------------------------------------------------------------------------------
1 | #!/bin/python3
2 |
3 | import esptool
4 |
5 | # fmt: off
6 | # Note: Bootloader for esp32-s3 starts at 0x0000, unlike several other ESP32 variants that start at 0x1000.
7 | esptool.main([
8 | '--chip', 'esp32s3',
9 | 'merge_bin', '-o', 'merged.bin',
10 | '--flash_size', '4MB',
11 | '0x0', './bootloader.bin',
12 | '0x8000', './partitions.bin',
13 | '0x10000', './app.bin',
14 | '0x353000', './staticfs.bin' # This is littlefs.bin, the github CI/CD pipeline renames it to staticfs.bin
15 | ])
16 | # fmt: on
17 |
--------------------------------------------------------------------------------
/chips/ESP32-S2/4MB/merge-image.py:
--------------------------------------------------------------------------------
1 | #!/bin/python3
2 |
3 | import esptool
4 |
5 | # fmt: off
6 | esptool.main([
7 | '--chip', 'esp32',
8 | 'merge_bin', '-o', 'merged.bin',
9 | '--flash_size', '4MB',
10 | '0x1000', './bootloader.bin',
11 | '0x8000', './partitions.bin',
12 | '0x10000', './app.bin',
13 | '0x353000', './staticfs.bin' # This is littlefs.bin, the github CI/CD pipeline renames it to staticfs.bin
14 | ])
15 | # fmt: on
16 |
--------------------------------------------------------------------------------
/chips/ESP32-S3/4MB/merge-image.py:
--------------------------------------------------------------------------------
1 | #!/bin/python3
2 |
3 | import esptool
4 |
5 | # fmt: off
6 | # Note: Bootloader for esp32-s3 starts at 0x0000, unlike several other ESP32 variants that start at 0x1000.
7 | esptool.main([
8 | '--chip', 'esp32s3',
9 | 'merge_bin', '-o', 'merged.bin',
10 | '--flash_size', '4MB',
11 | '0x0', './bootloader.bin',
12 | '0x8000', './partitions.bin',
13 | '0x10000', './app.bin',
14 | '0x353000', './staticfs.bin' # This is littlefs.bin, the github CI/CD pipeline renames it to staticfs.bin
15 | ])
16 | # fmt: on
17 |
--------------------------------------------------------------------------------
/chips/ESP32/4MB/merge-image.py:
--------------------------------------------------------------------------------
1 | #!/bin/python3
2 |
3 | import esptool
4 |
5 | # fmt: off
6 | esptool.main([
7 | '--chip', 'esp32',
8 | 'merge_bin', '-o', 'merged.bin',
9 | '--flash_size', '4MB',
10 | '0x1000', './bootloader.bin',
11 | '0x8000', './partitions.bin',
12 | '0x10000', './app.bin',
13 | '0x353000', './staticfs.bin' # This is littlefs.bin, the github CI/CD pipeline renames it to staticfs.bin
14 | ])
15 | # fmt: on
16 |
--------------------------------------------------------------------------------
/chips/partitions_4MB.csv:
--------------------------------------------------------------------------------
1 | # CURRENTLY NOT USED - KEPT FOR REFERENCE
2 | # OpenShock 4MB Partition Table - without OTA
3 | # Name, Type, SubType, Offset, Size, Flags
4 | # nvs, data, nvs, 0x009000, 0x005000,
5 | # otadata, data, ota, 0x00e000, 0x002000,
6 | # app0, app, ota_0, 0x010000, 0x340000,
7 | # config, data, spiffs, 0x350000, 0x003000,
8 | # static0, data, spiffs, 0x353000, 0x09D000,
9 | # coredump, data, coredump, 0x3F0000, 0x010000,
--------------------------------------------------------------------------------
/chips/partitions_4MB_OTA.csv:
--------------------------------------------------------------------------------
1 | # OpenShock 4MB Partition Table - with OTA
2 | # Name, Type, SubType, Offset, Size, Flags
3 | nvs, data, nvs, 0x009000, 0x005000,
4 | otadata, data, ota, 0x00e000, 0x002000,
5 | app0, app, ota_0, 0x010000, 0x1A0000,
6 | app1, app, ota_1, 0x1B0000, 0x1A0000,
7 | config, data, spiffs, 0x350000, 0x003000,
8 | static0, data, spiffs, 0x353000, 0x09D000,
9 | coredump, data, coredump, 0x3F0000, 0x010000,
--------------------------------------------------------------------------------
/frontend/.eslintignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 |
10 | # Package Managers
11 | pnpm-lock.yaml
12 | package-lock.json
13 | yarn.lock
14 |
15 | # Generated or imported files
16 | /components.json
17 | /src/lib/_fbs
18 | /src/lib/components/ui
19 |
--------------------------------------------------------------------------------
/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | test-results
2 | node_modules
3 |
4 | # Output
5 | .output
6 | .vercel
7 | .netlify
8 | .wrangler
9 | /.svelte-kit
10 | /build
11 |
12 | # OS
13 | .DS_Store
14 | Thumbs.db
15 |
16 | # Env
17 | .env
18 | .env.*
19 | !.env.example
20 | !.env.test
21 |
22 | # Vite
23 | vite.config.js.timestamp-*
24 | vite.config.ts.timestamp-*
25 |
--------------------------------------------------------------------------------
/frontend/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/frontend/.nvmrc:
--------------------------------------------------------------------------------
1 | 22.14.0
2 |
--------------------------------------------------------------------------------
/frontend/.prettierignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 |
10 | # Package Managers
11 | pnpm-lock.yaml
12 | package-lock.json
13 | yarn.lock
14 |
15 | # Generated or imported files
16 | /components.json
17 | /src/lib/_fbs
18 | /src/lib/components/ui
19 |
--------------------------------------------------------------------------------
/frontend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "semi": true,
4 | "useTabs": false,
5 | "singleQuote": true,
6 | "trailingComma": "es5",
7 | "printWidth": 100,
8 | "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
9 | "overrides": [
10 | { "files": "*.svelte", "options": { "parser": "svelte" } },
11 | { "files": "package*.json", "options": { "tabWidth": 2, "useTabs": true } }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://next.shadcn-svelte.com/schema.json",
3 | "style": "default",
4 | "tailwind": {
5 | "config": "tailwind.config.ts",
6 | "css": "src\\app.css",
7 | "baseColor": "neutral"
8 | },
9 | "aliases": {
10 | "components": "$lib/components",
11 | "utils": "$lib/utils",
12 | "ui": "$lib/components/ui",
13 | "hooks": "$lib/hooks"
14 | },
15 | "typescript": true,
16 | "registry": "https://next.shadcn-svelte.com/registry"
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/e2e/demo.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from '@playwright/test';
2 |
3 | test('home page has expected h3', async ({ page }) => {
4 | await page.goto('/');
5 | await expect(page.locator('h3')).toBeVisible();
6 | });
7 |
--------------------------------------------------------------------------------
/frontend/eslint.config.js:
--------------------------------------------------------------------------------
1 | import prettier from 'eslint-config-prettier';
2 | import js from '@eslint/js';
3 | import { includeIgnoreFile } from '@eslint/compat';
4 | import svelte from 'eslint-plugin-svelte';
5 | import globals from 'globals';
6 | import { fileURLToPath } from 'node:url';
7 | import ts from 'typescript-eslint';
8 | const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
9 |
10 | export default ts.config(
11 | includeIgnoreFile(gitignorePath),
12 | js.configs.recommended,
13 | ...ts.configs.recommended,
14 | ...svelte.configs['flat/recommended'],
15 | prettier,
16 | ...svelte.configs['flat/prettier'],
17 | {
18 | languageOptions: {
19 | globals: {
20 | ...globals.browser,
21 | ...globals.node,
22 | },
23 | },
24 | },
25 | {
26 | files: ['**/*.svelte'],
27 |
28 | languageOptions: {
29 | parserOptions: {
30 | parser: ts.parser,
31 | ecmaVersion: 2020,
32 | },
33 | },
34 | }
35 | );
36 |
--------------------------------------------------------------------------------
/frontend/playwright.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from '@playwright/test';
2 |
3 | export default defineConfig({
4 | webServer: {
5 | command: 'npm run build && npm run preview',
6 | port: 4173,
7 | },
8 |
9 | testDir: 'e2e',
10 | });
11 |
--------------------------------------------------------------------------------
/frontend/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://svelte.dev/docs/kit/types#app.d.ts
2 | // for information about these interfaces
3 | declare global {
4 | namespace App {
5 | // interface Error {}
6 | // interface Locals {}
7 | // interface PageData {}
8 | // interface PageState {}
9 | // interface Platform {}
10 | }
11 | }
12 |
13 | export {};
14 |
--------------------------------------------------------------------------------
/frontend/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | OpenShock Captive Portal
8 | %sveltekit.head%
9 |
10 |
11 | %sveltekit.body%
12 |
13 |
14 |
--------------------------------------------------------------------------------
/frontend/src/demo.spec.ts:
--------------------------------------------------------------------------------
1 | import { describe, it, expect } from 'vitest';
2 |
3 | describe('sum test', () => {
4 | it('adds 1 + 2 to equal 3', () => {
5 | expect(1 + 2).toBe(3);
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/AccountLinkCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
3 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
4 | import { AccountLinkCommand } from '$lib/_fbs/open-shock/serialization/local/account-link-command';
5 |
6 | export function SerializeAccountLinkCommand(linkCode: string): Uint8Array {
7 | const fbb = new FlatbufferBuilder(64);
8 |
9 | const linkCodeOffset = fbb.createString(linkCode);
10 |
11 | const cmdOffset = AccountLinkCommand.createAccountLinkCommand(fbb, linkCodeOffset);
12 |
13 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
14 | fbb,
15 | LocalToHubMessagePayload.AccountLinkCommand,
16 | cmdOffset
17 | );
18 |
19 | fbb.finish(payloadOffset);
20 |
21 | return fbb.asUint8Array();
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/SetEstopEnabledCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
3 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
4 | import { SetEstopEnabledCommand } from '$lib/_fbs/open-shock/serialization/local/set-estop-enabled-command';
5 |
6 | export function SerializeSetEstopEnabledCommand(enabled: boolean): Uint8Array {
7 | const fbb = new FlatbufferBuilder(64);
8 |
9 | const cmdOffset = SetEstopEnabledCommand.createSetEstopEnabledCommand(fbb, enabled);
10 |
11 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
12 | fbb,
13 | LocalToHubMessagePayload.SetEstopEnabledCommand,
14 | cmdOffset
15 | );
16 |
17 | fbb.finish(payloadOffset);
18 |
19 | return fbb.asUint8Array();
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/SetEstopPinCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
3 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
4 | import { SetEstopPinCommand } from '$lib/_fbs/open-shock/serialization/local/set-estop-pin-command';
5 |
6 | export function SerializeSetEstopPinCommand(pin: number): Uint8Array {
7 | const fbb = new FlatbufferBuilder(64);
8 |
9 | const cmdOffset = SetEstopPinCommand.createSetEstopPinCommand(fbb, pin);
10 |
11 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
12 | fbb,
13 | LocalToHubMessagePayload.SetEstopPinCommand,
14 | cmdOffset
15 | );
16 |
17 | fbb.finish(payloadOffset);
18 |
19 | return fbb.asUint8Array();
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/SetRfTxPinCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
3 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
4 | import { SetRfTxPinCommand } from '$lib/_fbs/open-shock/serialization/local/set-rf-tx-pin-command';
5 |
6 | export function SerializeSetRfTxPinCommand(pin: number): Uint8Array {
7 | const fbb = new FlatbufferBuilder(64);
8 |
9 | const cmdOffset = SetRfTxPinCommand.createSetRfTxPinCommand(fbb, pin);
10 |
11 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
12 | fbb,
13 | LocalToHubMessagePayload.SetRfTxPinCommand,
14 | cmdOffset
15 | );
16 |
17 | fbb.finish(payloadOffset);
18 |
19 | return fbb.asUint8Array();
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/WifiNetworkConnectCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
3 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
4 | import { WifiNetworkConnectCommand } from '$lib/_fbs/open-shock/serialization/local/wifi-network-connect-command';
5 |
6 | export function SerializeWifiNetworkConnectCommand(ssid: string): Uint8Array {
7 | const fbb = new FlatbufferBuilder(128);
8 |
9 | const ssidOffset = fbb.createString(ssid);
10 |
11 | const cmdOffset = WifiNetworkConnectCommand.createWifiNetworkConnectCommand(fbb, ssidOffset);
12 |
13 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
14 | fbb,
15 | LocalToHubMessagePayload.WifiNetworkConnectCommand,
16 | cmdOffset
17 | );
18 |
19 | fbb.finish(payloadOffset);
20 |
21 | return fbb.asUint8Array();
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/WifiNetworkDisconnectCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
3 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
4 | import { WifiNetworkDisconnectCommand } from '$lib/_fbs/open-shock/serialization/local/wifi-network-disconnect-command';
5 |
6 | export function SerializeWifiNetworkDisconnectCommand(): Uint8Array {
7 | const fbb = new FlatbufferBuilder(32);
8 |
9 | const cmdOffset = WifiNetworkDisconnectCommand.createWifiNetworkDisconnectCommand(fbb, true);
10 |
11 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
12 | fbb,
13 | LocalToHubMessagePayload.WifiNetworkDisconnectCommand,
14 | cmdOffset
15 | );
16 |
17 | fbb.finish(payloadOffset);
18 |
19 | return fbb.asUint8Array();
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/WifiNetworkForgetCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
3 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
4 | import { WifiNetworkForgetCommand } from '$lib/_fbs/open-shock/serialization/local/wifi-network-forget-command';
5 |
6 | export function SerializeWifiNetworkForgetCommand(ssid: string): Uint8Array {
7 | const fbb = new FlatbufferBuilder(128);
8 |
9 | const ssidOffset = fbb.createString(ssid);
10 |
11 | const cmdOffset = WifiNetworkForgetCommand.createWifiNetworkForgetCommand(fbb, ssidOffset);
12 |
13 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
14 | fbb,
15 | LocalToHubMessagePayload.WifiNetworkForgetCommand,
16 | cmdOffset
17 | );
18 |
19 | fbb.finish(payloadOffset);
20 |
21 | return fbb.asUint8Array();
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/WifiNetworkSaveCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
3 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
4 | import { WifiNetworkSaveCommand } from '$lib/_fbs/open-shock/serialization/local/wifi-network-save-command';
5 |
6 | export function SerializeWifiNetworkSaveCommand(
7 | ssid: string,
8 | password: string | null,
9 | connect: boolean
10 | ): Uint8Array {
11 | const fbb = new FlatbufferBuilder(128);
12 |
13 | const ssidOffset = fbb.createString(ssid);
14 | let passwordOffset = 0;
15 | if (password) {
16 | passwordOffset = fbb.createString(password);
17 | }
18 |
19 | const cmdOffset = WifiNetworkSaveCommand.createWifiNetworkSaveCommand(
20 | fbb,
21 | ssidOffset,
22 | passwordOffset,
23 | connect
24 | );
25 |
26 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
27 | fbb,
28 | LocalToHubMessagePayload.WifiNetworkSaveCommand,
29 | cmdOffset
30 | );
31 |
32 | fbb.finish(payloadOffset);
33 |
34 | return fbb.asUint8Array();
35 | }
36 |
--------------------------------------------------------------------------------
/frontend/src/lib/Serializers/WifiScanCommand.ts:
--------------------------------------------------------------------------------
1 | import { Builder as FlatbufferBuilder } from 'flatbuffers';
2 | import { WifiScanCommand } from '$lib/_fbs/open-shock/serialization/local/wifi-scan-command';
3 | import { LocalToHubMessage } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message';
4 | import { LocalToHubMessagePayload } from '$lib/_fbs/open-shock/serialization/local/local-to-hub-message-payload';
5 |
6 | export function SerializeWifiScanCommand(scan: boolean): Uint8Array {
7 | const fbb = new FlatbufferBuilder(32);
8 |
9 | const cmdOffset = WifiScanCommand.createWifiScanCommand(fbb, scan);
10 |
11 | const payloadOffset = LocalToHubMessage.createLocalToHubMessage(
12 | fbb,
13 | LocalToHubMessagePayload.WifiScanCommand,
14 | cmdOffset
15 | );
16 |
17 | fbb.finish(payloadOffset);
18 |
19 | return fbb.asUint8Array();
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/TypeGuards/BasicGuards.ts:
--------------------------------------------------------------------------------
1 | export function isObject(data: unknown): data is object {
2 | return typeof data === 'object' && data !== null;
3 | }
4 | export function isString(value: unknown): value is string {
5 | return typeof value === 'string' || value instanceof String;
6 | }
7 | export function isNumber(value: unknown): value is number {
8 | return typeof value === 'number' && isFinite(value);
9 | }
10 | export function isArrayBuffer(value: unknown): value is ArrayBuffer {
11 | return value instanceof ArrayBuffer;
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/configuration.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export { BackendConfig } from './configuration/backend-config';
6 | export { CaptivePortalConfig } from './configuration/captive-portal-config';
7 | export { EStopConfig } from './configuration/estop-config';
8 | export { HubConfig } from './configuration/hub-config';
9 | export { OtaUpdateChannel } from './configuration/ota-update-channel';
10 | export { OtaUpdateConfig } from './configuration/ota-update-config';
11 | export { OtaUpdateStep } from './configuration/ota-update-step';
12 | export { RFConfig } from './configuration/rfconfig';
13 | export { SerialInputConfig } from './configuration/serial-input-config';
14 | export { WiFiConfig } from './configuration/wi-fi-config';
15 | export { WiFiCredentials } from './configuration/wi-fi-credentials';
16 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/configuration/ota-update-channel.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum OtaUpdateChannel {
6 | Stable = 0,
7 | Beta = 1,
8 | Develop = 2
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/configuration/ota-update-step.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum OtaUpdateStep {
6 | None = 0,
7 | Updating = 1,
8 | Updated = 2,
9 | Validating = 3,
10 | Validated = 4,
11 | RollingBack = 5
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/gateway.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export { BootStatus } from './gateway/boot-status';
6 | export { HubToGatewayMessage } from './gateway/hub-to-gateway-message';
7 | export { HubToGatewayMessagePayload } from './gateway/hub-to-gateway-message-payload';
8 | export { OtaUpdateFailed } from './gateway/ota-update-failed';
9 | export { OtaUpdateProgress } from './gateway/ota-update-progress';
10 | export { OtaUpdateStarted } from './gateway/ota-update-started';
11 | export { Pong } from './gateway/pong';
12 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/gateway/ping.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | import * as flatbuffers from 'flatbuffers';
6 |
7 | export class Ping {
8 | bb: flatbuffers.ByteBuffer|null = null;
9 | bb_pos = 0;
10 | __init(i:number, bb:flatbuffers.ByteBuffer):Ping {
11 | this.bb_pos = i;
12 | this.bb = bb;
13 | return this;
14 | }
15 |
16 | static getRootAsPing(bb:flatbuffers.ByteBuffer, obj?:Ping):Ping {
17 | return (obj || new Ping()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
18 | }
19 |
20 | static getSizePrefixedRootAsPing(bb:flatbuffers.ByteBuffer, obj?:Ping):Ping {
21 | bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
22 | return (obj || new Ping()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
23 | }
24 |
25 | unixUtcTime():bigint {
26 | const offset = this.bb!.__offset(this.bb_pos, 4);
27 | return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
28 | }
29 |
30 | static startPing(builder:flatbuffers.Builder) {
31 | builder.startObject(1);
32 | }
33 |
34 | static addUnixUtcTime(builder:flatbuffers.Builder, unixUtcTime:bigint) {
35 | builder.addFieldInt64(0, unixUtcTime, BigInt('0'));
36 | }
37 |
38 | static endPing(builder:flatbuffers.Builder):flatbuffers.Offset {
39 | const offset = builder.endObject();
40 | return offset;
41 | }
42 |
43 | static createPing(builder:flatbuffers.Builder, unixUtcTime:bigint):flatbuffers.Offset {
44 | Ping.startPing(builder);
45 | Ping.addUnixUtcTime(builder, unixUtcTime);
46 | return Ping.endPing(builder);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/gateway/trigger-type.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum TriggerType {
6 | /**
7 | * Restart the hub
8 | */
9 | Restart = 0,
10 |
11 | /**
12 | * Trigger the emergency stop on the hub, this does however not allow for resetting it
13 | */
14 | EmergencyStop = 1,
15 |
16 | /**
17 | * Enable the captive portal
18 | */
19 | CaptivePortalEnable = 2,
20 |
21 | /**
22 | * Disable the captive portal
23 | */
24 | CaptivePortalDisable = 3
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/gateway/trigger.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | import * as flatbuffers from 'flatbuffers';
6 |
7 | import { TriggerType } from '../../../open-shock/serialization/gateway/trigger-type';
8 |
9 |
10 | export class Trigger {
11 | bb: flatbuffers.ByteBuffer|null = null;
12 | bb_pos = 0;
13 | __init(i:number, bb:flatbuffers.ByteBuffer):Trigger {
14 | this.bb_pos = i;
15 | this.bb = bb;
16 | return this;
17 | }
18 |
19 | static getRootAsTrigger(bb:flatbuffers.ByteBuffer, obj?:Trigger):Trigger {
20 | return (obj || new Trigger()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
21 | }
22 |
23 | static getSizePrefixedRootAsTrigger(bb:flatbuffers.ByteBuffer, obj?:Trigger):Trigger {
24 | bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
25 | return (obj || new Trigger()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
26 | }
27 |
28 | type():TriggerType {
29 | const offset = this.bb!.__offset(this.bb_pos, 4);
30 | return offset ? this.bb!.readUint8(this.bb_pos + offset) : TriggerType.Restart;
31 | }
32 |
33 | static startTrigger(builder:flatbuffers.Builder) {
34 | builder.startObject(1);
35 | }
36 |
37 | static addType(builder:flatbuffers.Builder, type:TriggerType) {
38 | builder.addFieldInt8(0, type, TriggerType.Restart);
39 | }
40 |
41 | static endTrigger(builder:flatbuffers.Builder):flatbuffers.Offset {
42 | const offset = builder.endObject();
43 | return offset;
44 | }
45 |
46 | static createTrigger(builder:flatbuffers.Builder, type:TriggerType):flatbuffers.Offset {
47 | Trigger.startTrigger(builder);
48 | Trigger.addType(builder, type);
49 | return Trigger.endTrigger(builder);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/local/account-link-result-code.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum AccountLinkResultCode {
6 | Success = 0,
7 | CodeRequired = 1,
8 | InvalidCodeLength = 2,
9 | NoInternetConnection = 3,
10 | InvalidCode = 4,
11 | RateLimited = 5,
12 | InternalError = 6
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/local/set-estop-pin-command.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | import * as flatbuffers from 'flatbuffers';
6 |
7 | export class SetEstopPinCommand {
8 | bb: flatbuffers.ByteBuffer|null = null;
9 | bb_pos = 0;
10 | __init(i:number, bb:flatbuffers.ByteBuffer):SetEstopPinCommand {
11 | this.bb_pos = i;
12 | this.bb = bb;
13 | return this;
14 | }
15 |
16 | static getRootAsSetEstopPinCommand(bb:flatbuffers.ByteBuffer, obj?:SetEstopPinCommand):SetEstopPinCommand {
17 | return (obj || new SetEstopPinCommand()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
18 | }
19 |
20 | static getSizePrefixedRootAsSetEstopPinCommand(bb:flatbuffers.ByteBuffer, obj?:SetEstopPinCommand):SetEstopPinCommand {
21 | bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
22 | return (obj || new SetEstopPinCommand()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
23 | }
24 |
25 | pin():number {
26 | const offset = this.bb!.__offset(this.bb_pos, 4);
27 | return offset ? this.bb!.readInt8(this.bb_pos + offset) : 0;
28 | }
29 |
30 | static startSetEstopPinCommand(builder:flatbuffers.Builder) {
31 | builder.startObject(1);
32 | }
33 |
34 | static addPin(builder:flatbuffers.Builder, pin:number) {
35 | builder.addFieldInt8(0, pin, 0);
36 | }
37 |
38 | static endSetEstopPinCommand(builder:flatbuffers.Builder):flatbuffers.Offset {
39 | const offset = builder.endObject();
40 | return offset;
41 | }
42 |
43 | static createSetEstopPinCommand(builder:flatbuffers.Builder, pin:number):flatbuffers.Offset {
44 | SetEstopPinCommand.startSetEstopPinCommand(builder);
45 | SetEstopPinCommand.addPin(builder, pin);
46 | return SetEstopPinCommand.endSetEstopPinCommand(builder);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/local/set-gpioresult-code.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum SetGPIOResultCode {
6 | Success = 0,
7 | InvalidPin = 1,
8 | InternalError = 2
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/local/set-rf-tx-pin-command.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | import * as flatbuffers from 'flatbuffers';
6 |
7 | export class SetRfTxPinCommand {
8 | bb: flatbuffers.ByteBuffer|null = null;
9 | bb_pos = 0;
10 | __init(i:number, bb:flatbuffers.ByteBuffer):SetRfTxPinCommand {
11 | this.bb_pos = i;
12 | this.bb = bb;
13 | return this;
14 | }
15 |
16 | static getRootAsSetRfTxPinCommand(bb:flatbuffers.ByteBuffer, obj?:SetRfTxPinCommand):SetRfTxPinCommand {
17 | return (obj || new SetRfTxPinCommand()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
18 | }
19 |
20 | static getSizePrefixedRootAsSetRfTxPinCommand(bb:flatbuffers.ByteBuffer, obj?:SetRfTxPinCommand):SetRfTxPinCommand {
21 | bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
22 | return (obj || new SetRfTxPinCommand()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
23 | }
24 |
25 | pin():number {
26 | const offset = this.bb!.__offset(this.bb_pos, 4);
27 | return offset ? this.bb!.readInt8(this.bb_pos + offset) : 0;
28 | }
29 |
30 | static startSetRfTxPinCommand(builder:flatbuffers.Builder) {
31 | builder.startObject(1);
32 | }
33 |
34 | static addPin(builder:flatbuffers.Builder, pin:number) {
35 | builder.addFieldInt8(0, pin, 0);
36 | }
37 |
38 | static endSetRfTxPinCommand(builder:flatbuffers.Builder):flatbuffers.Offset {
39 | const offset = builder.endObject();
40 | return offset;
41 | }
42 |
43 | static createSetRfTxPinCommand(builder:flatbuffers.Builder, pin:number):flatbuffers.Offset {
44 | SetRfTxPinCommand.startSetRfTxPinCommand(builder);
45 | SetRfTxPinCommand.addPin(builder, pin);
46 | return SetRfTxPinCommand.endSetRfTxPinCommand(builder);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/local/wifi-scan-command.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | import * as flatbuffers from 'flatbuffers';
6 |
7 | export class WifiScanCommand {
8 | bb: flatbuffers.ByteBuffer|null = null;
9 | bb_pos = 0;
10 | __init(i:number, bb:flatbuffers.ByteBuffer):WifiScanCommand {
11 | this.bb_pos = i;
12 | this.bb = bb;
13 | return this;
14 | }
15 |
16 | static getRootAsWifiScanCommand(bb:flatbuffers.ByteBuffer, obj?:WifiScanCommand):WifiScanCommand {
17 | return (obj || new WifiScanCommand()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
18 | }
19 |
20 | static getSizePrefixedRootAsWifiScanCommand(bb:flatbuffers.ByteBuffer, obj?:WifiScanCommand):WifiScanCommand {
21 | bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
22 | return (obj || new WifiScanCommand()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
23 | }
24 |
25 | run():boolean {
26 | const offset = this.bb!.__offset(this.bb_pos, 4);
27 | return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
28 | }
29 |
30 | static startWifiScanCommand(builder:flatbuffers.Builder) {
31 | builder.startObject(1);
32 | }
33 |
34 | static addRun(builder:flatbuffers.Builder, run:boolean) {
35 | builder.addFieldInt8(0, +run, +false);
36 | }
37 |
38 | static endWifiScanCommand(builder:flatbuffers.Builder):flatbuffers.Offset {
39 | const offset = builder.endObject();
40 | return offset;
41 | }
42 |
43 | static createWifiScanCommand(builder:flatbuffers.Builder, run:boolean):flatbuffers.Offset {
44 | WifiScanCommand.startWifiScanCommand(builder);
45 | WifiScanCommand.addRun(builder, run);
46 | return WifiScanCommand.endWifiScanCommand(builder);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/types.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export { WifiScanStatus } from './types/wifi-scan-status';
6 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/types/firmware-boot-type.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum FirmwareBootType {
6 | Normal = 0,
7 | NewFirmware = 1,
8 | Rollback = 2
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/types/ota-update-progress-task.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum OtaUpdateProgressTask {
6 | FetchingMetadata = 0,
7 | PreparingForUpdate = 1,
8 | FlashingFilesystem = 2,
9 | VerifyingFilesystem = 3,
10 | FlashingApplication = 4,
11 | MarkingApplicationBootable = 5,
12 | Rebooting = 6
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/types/shocker-command-type.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum ShockerCommandType {
6 | Stop = 0,
7 | Shock = 1,
8 | Vibrate = 2,
9 | Sound = 3
10 | }
11 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/types/shocker-model-type.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum ShockerModelType {
6 | CaiXianlin = 0,
7 | Petrainer = 1,
8 | Petrainer998DR = 2
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/types/wifi-auth-mode.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum WifiAuthMode {
6 | Open = 0,
7 | WEP = 1,
8 | WPA_PSK = 2,
9 | WPA2_PSK = 3,
10 | WPA_WPA2_PSK = 4,
11 | WPA2_ENTERPRISE = 5,
12 | WPA3_PSK = 6,
13 | WPA2_WPA3_PSK = 7,
14 | WAPI_PSK = 8,
15 | UNKNOWN = 9
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/types/wifi-network-event-type.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum WifiNetworkEventType {
6 | Discovered = 0,
7 | Updated = 1,
8 | Lost = 2,
9 | Saved = 3,
10 | Removed = 4,
11 | Connected = 5,
12 | Disconnected = 6
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/lib/_fbs/open-shock/serialization/types/wifi-scan-status.ts:
--------------------------------------------------------------------------------
1 | // automatically generated by the FlatBuffers compiler, do not modify
2 |
3 | /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
4 |
5 | export enum WifiScanStatus {
6 | Started = 0,
7 | InProgress = 1,
8 | Completed = 2,
9 | TimedOut = 3,
10 | Aborted = 4,
11 | Error = 5
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/Layout/Footer.svelte:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/Layout/Header.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
8 |
9 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/button/index.ts:
--------------------------------------------------------------------------------
1 | import Root, {
2 | type ButtonProps,
3 | type ButtonSize,
4 | type ButtonVariant,
5 | buttonVariants,
6 | } from "./button.svelte";
7 |
8 | export {
9 | Root,
10 | type ButtonProps as Props,
11 | //
12 | Root as Button,
13 | buttonVariants,
14 | type ButtonProps,
15 | type ButtonSize,
16 | type ButtonVariant,
17 | };
18 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dialog/dialog-content.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
30 | {@render children?.()}
31 |
34 |
35 | Close
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dialog/dialog-description.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dialog/dialog-footer.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 | {@render children?.()}
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dialog/dialog-header.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 | {@render children?.()}
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dialog/dialog-overlay.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
20 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dialog/dialog-title.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dialog/index.ts:
--------------------------------------------------------------------------------
1 | import { Dialog as DialogPrimitive } from "bits-ui";
2 |
3 | import Title from "./dialog-title.svelte";
4 | import Footer from "./dialog-footer.svelte";
5 | import Header from "./dialog-header.svelte";
6 | import Overlay from "./dialog-overlay.svelte";
7 | import Content from "./dialog-content.svelte";
8 | import Description from "./dialog-description.svelte";
9 |
10 | const Root = DialogPrimitive.Root;
11 | const Trigger = DialogPrimitive.Trigger;
12 | const Close = DialogPrimitive.Close;
13 | const Portal = DialogPrimitive.Portal;
14 |
15 | export {
16 | Root,
17 | Title,
18 | Portal,
19 | Footer,
20 | Header,
21 | Trigger,
22 | Overlay,
23 | Content,
24 | Description,
25 | Close,
26 | //
27 | Root as Dialog,
28 | Title as DialogTitle,
29 | Portal as DialogPortal,
30 | Footer as DialogFooter,
31 | Header as DialogHeader,
32 | Trigger as DialogTrigger,
33 | Overlay as DialogOverlay,
34 | Content as DialogContent,
35 | Description as DialogDescription,
36 | Close as DialogClose,
37 | };
38 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
30 | {#snippet children({ checked, indeterminate })}
31 |
32 | {#if indeterminate}
33 |
34 | {:else}
35 |
36 | {/if}
37 |
38 | {@render childrenProp?.()}
39 | {/snippet}
40 |
41 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
26 |
27 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
24 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
22 | {@render children?.()}
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
22 | {#snippet children({ checked })}
23 |
24 | {#if checked}
25 |
26 | {/if}
27 |
28 | {@render childrenProp?.({ checked })}
29 | {/snippet}
30 |
31 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 | {@render children?.()}
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
20 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
26 | {@render children?.()}
27 |
28 |
29 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/dropdown-menu/index.ts:
--------------------------------------------------------------------------------
1 | import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
2 | import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
3 | import Content from "./dropdown-menu-content.svelte";
4 | import GroupHeading from "./dropdown-menu-group-heading.svelte";
5 | import Item from "./dropdown-menu-item.svelte";
6 | import Label from "./dropdown-menu-label.svelte";
7 | import RadioItem from "./dropdown-menu-radio-item.svelte";
8 | import Separator from "./dropdown-menu-separator.svelte";
9 | import Shortcut from "./dropdown-menu-shortcut.svelte";
10 | import SubContent from "./dropdown-menu-sub-content.svelte";
11 | import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
12 |
13 | const Sub = DropdownMenuPrimitive.Sub;
14 | const Root = DropdownMenuPrimitive.Root;
15 | const Trigger = DropdownMenuPrimitive.Trigger;
16 | const Group = DropdownMenuPrimitive.Group;
17 | const RadioGroup = DropdownMenuPrimitive.RadioGroup;
18 |
19 | export {
20 | CheckboxItem,
21 | Content,
22 | Root as DropdownMenu,
23 | CheckboxItem as DropdownMenuCheckboxItem,
24 | Content as DropdownMenuContent,
25 | Group as DropdownMenuGroup,
26 | GroupHeading as DropdownMenuGroupHeading,
27 | Item as DropdownMenuItem,
28 | Label as DropdownMenuLabel,
29 | RadioGroup as DropdownMenuRadioGroup,
30 | RadioItem as DropdownMenuRadioItem,
31 | Separator as DropdownMenuSeparator,
32 | Shortcut as DropdownMenuShortcut,
33 | Sub as DropdownMenuSub,
34 | SubContent as DropdownMenuSubContent,
35 | SubTrigger as DropdownMenuSubTrigger,
36 | Trigger as DropdownMenuTrigger,
37 | Group,
38 | GroupHeading,
39 | Item,
40 | Label,
41 | RadioGroup,
42 | RadioItem,
43 | Root,
44 | Separator,
45 | Shortcut,
46 | Sub,
47 | SubContent,
48 | SubTrigger,
49 | Trigger,
50 | };
51 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/input/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./input.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Input,
7 | };
8 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/input/input.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 | {#if type === "file"}
24 |
35 | {:else}
36 |
46 | {/if}
47 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/label/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./label.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Label,
7 | };
8 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/label/label.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
20 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/scroll-area/index.ts:
--------------------------------------------------------------------------------
1 | import Scrollbar from "./scroll-area-scrollbar.svelte";
2 | import Root from "./scroll-area.svelte";
3 |
4 | export {
5 | Root,
6 | Scrollbar,
7 | //,
8 | Root as ScrollArea,
9 | Scrollbar as ScrollAreaScrollbar,
10 | };
11 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
25 | {@render children?.()}
26 |
29 |
30 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/scroll-area/scroll-area.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
23 | {@render children?.()}
24 |
25 | {#if orientation === "vertical" || orientation === "both"}
26 |
27 | {/if}
28 | {#if orientation === "horizontal" || orientation === "both"}
29 |
30 | {/if}
31 |
32 |
33 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/sonner/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Toaster } from "./sonner.svelte";
2 |
--------------------------------------------------------------------------------
/frontend/src/lib/components/ui/sonner/sonner.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
21 |
--------------------------------------------------------------------------------
/frontend/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | // place files you want to import through the `$lib` alias in this folder.
2 |
--------------------------------------------------------------------------------
/frontend/src/lib/stores/UsedPinsStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | const { subscribe, update } = writable