From 31c8e8303f9a9b8976a93424c4384257b6fb4068 Mon Sep 17 00:00:00 2001 From: MatiasG19 <73800355+MatiasG19@users.noreply.github.com> Date: Mon, 3 Jul 2023 00:47:36 +0200 Subject: [PATCH] ci: Add CI (#5) * Add ci * Fix path * Fix path * Fix path * Fix checkout * Add vscode format on save * Format server * Fix path * Fix path * Add ci badge to readme * Fix path * Update ci.yml * Use different gitgub action for compile * Update ci.yml * use ubuntu * Rename .ino file * Revert switch case * Update src.ino * Update src.ino * Mover format check to back * Add prettier * Add web format check * Update ci.yml * Update ci.yml * Update ci.yml * Update ci.yml * Update ci.yml * Update ci.yml * Update ci.yml * Update ci.yml --- .github/workflows/ci.yml | 88 +++++++++++++ .vscode/settings.json | 3 + README.md | 2 +- docs/BuildInstructions.md | 4 +- server/.clang-format | 192 +++++++++++++++++++++++++++++ server/{server.ino => src/src.ino} | 100 ++++++++------- web/.gitignore | 130 +++++++++++++++++++ web/package.json | 15 +++ web/yarn.lock | 8 ++ 9 files changed, 487 insertions(+), 55 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .vscode/settings.json create mode 100644 server/.clang-format rename server/{server.ino => src/src.ino} (59%) create mode 100644 web/.gitignore create mode 100644 web/package.json create mode 100644 web/yarn.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a8d5341 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,88 @@ +name: ci + +on: [push, pull_request] + +env: + SERVER_PATH: server/src/ + WEB_PATH: web/ + +jobs: + Server-Compile: + runs-on: ubuntu-latest + + strategy: + matrix: + fqbn: + - arduino:avr:uno + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Arduino CLI + uses: arduino/compile-sketches@v1 + with: + fqbn: ${{ matrix.fqbn }} + libraries: | + - name: Ethernet + - name: SD + sketch-paths: | + - ${{ env.SERVER_PATH }} + + Server-Format-Check: + needs: [Server-Compile] + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Setup Clang Formatter + uses: actions/checkout@v3 + with: + repository: adafruit/ci-arduino + path: ci + + - name: Check correct code formatting with clang-format + run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" --extensions "ino" -r ${{ env.SERVER_PATH }} + + Web-Format-Check: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "YARN_CACHE_DIR_PATH=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Cache yarn dependencies + uses: actions/cache@v3 + id: yarn-cache + with: + path: | + ${{ steps.yarn-cache-dir-path.outputs.YARN_CACHE_DIR_PATH }} + **/node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install dependecies + working-directory: ${{ env.WEB_PATH }} + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: yarn --frozen-lockfile + + - name: Check format + working-directory: ${{ env.WEB_PATH }} + run: yarn check-format diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ad92582 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": true +} diff --git a/README.md b/README.md index 5af4023..1d83b02 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Arduino Remote Switch +# Arduino Remote Switch [![ci](https://github.com/MatiasG19/arduino-remote-switch/actions/workflows/ci.yml/badge.svg)](https://github.com/MatiasG19/arduino-remote-switch/actions/workflows/ci.yml) Remote switch to turn on, off, reset or kill PC via a web interface. diff --git a/docs/BuildInstructions.md b/docs/BuildInstructions.md index a605d68..9313a8b 100644 --- a/docs/BuildInstructions.md +++ b/docs/BuildInstructions.md @@ -24,8 +24,8 @@ 3. Put SD card into ethernet shield. 4. Connect Arduino to a powerd on PC via USB and the shield to a router via ethernet. 5. Open router configuration, set a static IP range and choose a free IP address. -6. Set the IP address in the `server.ino` file and save. -7. Open Arduino IDE and upload `server.ino` to Arduino. +6. Set the IP address in the `src.ino` file and save. +7. Open Arduino IDE and upload `src.ino` to Arduino. 8. Test if the website can be reached by typing the IP into the webbrowser. 9. Unplug all the cables from the Arduino for the next steps. diff --git a/server/.clang-format b/server/.clang-format new file mode 100644 index 0000000..48b2c67 --- /dev/null +++ b/server/.clang-format @@ -0,0 +1,192 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: false +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Right +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/server/server.ino b/server/src/src.ino similarity index 59% rename from server/server.ino rename to server/src/src.ino index f7446c1..366e3a9 100644 --- a/server/server.ino +++ b/server/src/src.ino @@ -1,14 +1,14 @@ #include #include -byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; IPAddress ip(192, 168, 0, 10); EthernetServer server(80); long delayStart; const int IN_PIN_POWER_LED = 7; const int OUT_PIN_POWER = 8, OUT_PIN_RESET = 9; -int POWER_LED_OFF_DELAY = 3000; // ms +const int POWER_LED_OFF_DELAY = 3000; // ms // Commands bool powerOn, standBy, reset, kill; @@ -47,11 +47,10 @@ void setup() { void loop() { // Read inputs - if(digitalRead(IN_PIN_POWER_LED) == 0) { + if (digitalRead(IN_PIN_POWER_LED) == 0) { powerLed = true; delayStart = millis(); - } - else if(millis() - delayStart > POWER_LED_OFF_DELAY) + } else if (millis() - delayStart > POWER_LED_OFF_DELAY) powerLed = false; // Server @@ -63,48 +62,46 @@ void loop() { request = ""; while (client.connected()) { if (client.available()) { - char reqChar = client.read(); // Read 1 byte (character) from client + char reqChar = client.read(); // Read 1 byte (character) from client - if(currentLineIsBlank == true) + if (currentLineIsBlank == true) continue; - else if (reqChar == '\n' && request.length() > 0) { + else if (reqChar == '\n' && request.length() > 0) { currentLineIsBlank = true; continue; - } + } request += reqChar; - } - else { + } else { Serial.print("Request: "); Serial.println(request); - if(request.length() > 0) { - if(request.startsWith("GET /")) { - request.replace("GET /", ""); - sendResponse(request.substring(0, request.indexOf(" ")), client); - break; - } - else { - client.println("HTTP/1.1 404 Not Found\n\r"); + if (request.length() > 0) { + if (request.startsWith("GET /")) { + request.replace("GET /", ""); + sendResponse(request.substring(0, request.indexOf(" ")), client); + break; + } else { + client.println("HTTP/1.1 404 Not Found\n\r"); break; } } } } - delay(1); // Give the web browser time to receive the data - client.stop(); + delay(1); // Give the web browser time to receive the data + client.stop(); } // Control outputs - if(powerOn) { + if (powerOn) { controlOutput(OUT_PIN_POWER, 500); powerOn = false; - } else if(standBy) { + } else if (standBy) { controlOutput(OUT_PIN_POWER, 500); standBy = false; - } else if(reset) { + } else if (reset) { controlOutput(OUT_PIN_RESET, 500); reset = false; - } else if(kill) { + } else if (kill) { Serial.println("kill"); controlOutput(OUT_PIN_POWER, 5000); kill = false; @@ -115,45 +112,44 @@ void sendResponse(String request, EthernetClient client) { client.println("HTTP/1.1 200 OK"); // Send file to client - if(request == "") { + if (request == "") { client.println("Content-Type: text/html\n\r\n\r"); File webFile = SD.open(request); if (webFile) { while (webFile.available()) { - client.write(webFile.read()); + client.write(webFile.read()); } webFile.close(); - } + } } // Button actions and status request else { client.println("\n\r\n\r"); - switch(request) { - case "powerStatus": - if(powerLed) client.write("powerStatus:on"); - else client.write("powerStatus:off"); - break; - case "powerOn": - if (!powerLed) powerOn = true; - break; - case "standBy": - if (powerLed) standBy = true; - break; - case "reset": - if (powerLed) reset = true; - break; - case "kill": - if (powerLed) kill = true; - break; - default: - client.println("HTTP/1.1 404 Not Found\n\r"); - } + if (request == "powerStatus") { + if (powerLed) + client.write("powerStatus:on"); + else + client.write("powerStatus:off"); + } else if (request == "powerOn") { + if (!powerLed) + powerOn = true; + } else if (request == "standBy") { + if (powerLed) + standBy = true; + } else if (request == "reset") { + if (powerLed) + reset = true; + } else if (request == "kill") { + if (powerLed) + kill = true; + } else + client.println("HTTP/1.1 404 Not Found\n\r"); } } void controlOutput(int output, int delayTime) { - digitalWrite(output, HIGH); - delay(delayTime); + digitalWrite(output, HIGH); + delay(delayTime); digitalWrite(output, LOW); - delay(3000); -} + delay(3000); +} \ No newline at end of file diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..c6bba59 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,130 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/web/package.json b/web/package.json new file mode 100644 index 0000000..aa783f0 --- /dev/null +++ b/web/package.json @@ -0,0 +1,15 @@ +{ + "name": "arduino-remote-switch", + "version": "1.0.0", + "main": "index.htm", + "repository": "https://github.com/MatiasG19/arduino-remote-switch", + "author": "Matiasg19", + "license": "GNU GPL V3", + "private": true, + "scripts": { + "check-format": "yarn prettier --check ." + }, + "devDependencies": { + "prettier": "2.8.8" + } +} diff --git a/web/yarn.lock b/web/yarn.lock new file mode 100644 index 0000000..7c65ca6 --- /dev/null +++ b/web/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +prettier@2.8.8: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==