Compare commits

...

661 Commits

Author SHA1 Message Date
Rick Carlino c93be153e6
Merge pull request #1203 from FarmBot/recovery_release
Late additions
2020-05-19 13:45:41 -05:00
Rick Carlino c2b92722a8
Merge pull request #1202 from FarmBot/prod_release
Prod Release, v10.0.0
2020-05-19 09:56:53 -05:00
Rick Carlino 8e08b9d182 Release v10.0.0, formatting updates 2020-05-19 09:49:44 -05:00
Rick Carlino 1047f56e1c Release v10.0.0 2020-05-19 09:38:59 -05:00
Rick Carlino e897b763f5
Merge pull request #1201 from FarmBot/qa/10.0.0
FBOS v10.0.0
2020-05-19 09:34:18 -05:00
Rick Carlino 064ee310d9 New release to debug OTA issues 2020-05-18 17:19:45 -05:00
gabrielburnworth 6cf1dc9159 [10.0.0-rc46] update arduino firmware (6.5.22) 2020-05-18 13:29:37 -07:00
gabrielburnworth c5929a7429 [10.0.0-rc45] update arduino firmware (6.5.21) 2020-05-18 11:50:37 -07:00
Rick Carlino 6deea2785d Fix a bug where FBOS would not honor an "AUTO UPDATE" value of "false". 2020-05-18 13:32:02 -05:00
Rick Carlino 1158263405 v10-r43 2020-05-18 09:38:57 -05:00
Rick Carlino 6422ba1bcd Merge branch 'qa/homing_updates' of github.com:FarmBot/farmbot_os into qa/10.0.0 2020-05-18 09:37:20 -05:00
Rick Carlino 65d50540d2 v10-r42 2020-05-18 09:17:03 -05:00
Rick Carlino 336b21ef31 Documentation and test fixes. 2020-05-18 09:16:35 -05:00
gabrielburnworth d03e5d9ec7 [10.0.0-rc42] update arduino firmware (6.5.20) 2020-05-17 13:16:09 -07:00
gabrielburnworth 3901b02913 Merge branch 'staging' of https://github.com/FarmBot/farmbot_os into qa/homing_updates 2020-05-17 13:15:22 -07:00
Rick Carlino 8309412f49 If stale records are found, abort, wait, retry 2020-05-17 14:45:12 -05:00
Rick Carlino 7431ecf800 Try refreshing the data instead 2020-05-17 13:25:16 -05:00
Rick Carlino 2eb178279f Try refreshing the data instead 2020-05-17 13:21:01 -05:00
Rick Carlino 27da00be16 Try refreshing the data instead 2020-05-17 13:13:16 -05:00
Rick Carlino 7355fd25fb Fix typo. 2020-05-17 12:41:10 -05:00
Rick Carlino 3b256f14f6 Drilling down deeper into isolating stale data bug 2020-05-17 12:08:37 -05:00
Rick Carlino c5b40d9b6d Typo 2020-05-17 11:09:01 -05:00
Rick Carlino 5abd596957 Begin debugging DirtyWorker 2020-05-17 11:04:55 -05:00
Rick Carlino 75604c5b34 More debug points 2020-05-17 09:40:48 -05:00
Rick Carlino 4317a32a1c CI Fixes 2020-05-16 22:12:42 -05:00
Rick Carlino e590b5eb6b Try different nerves_system_br 2020-05-16 22:09:27 -05:00
Rick Carlino 12ee219ba6 10.0.0-rc33: Add debug points 2020-05-16 19:02:10 -05:00
Rick Carlino 004f7bb1d7 TODO: Determine source of stale point data in MARK AS 2020-05-16 17:33:48 -05:00
Gabriel Burnworth 6255515fa2
Update RELEASE_NOTES.md (v10) [skip ci] 2020-05-16 09:29:55 -07:00
Rick Carlino 881585f254 Remove unusued alias 2020-05-16 10:27:33 -05:00
Rick Carlino aecb77b48a Minor formatting issues. 2020-05-16 09:11:49 -05:00
Rick Carlino 02f16082b9 Begin debugging `clean_params` 2020-05-15 20:11:37 -05:00
Rick Carlino 70b5fb18bb v10.0.0-rc32 2020-05-15 18:42:16 -05:00
Rick Carlino e1f79aeaf5 Partial re-write of DirtyWOrker module 2020-05-15 18:24:57 -05:00
gabrielburnworth 13fa880204 [10.0.0-rc30] update arduino firmware (6.5.19) 2020-05-15 12:49:32 -07:00
Gabriel Burnworth 3449864bc5
Update FEATURE_MIN_VERSIONS.json [skip ci] 2020-05-15 07:51:32 -07:00
Rick Carlino 1807e5c0d3
Merge pull request #1200 from FarmBot/qa/10.0.0
v10.0.0
2020-05-15 09:21:59 -05:00
Rick Carlino 88b440ee59 ✔️ v10.0.0 Ready for final QA 2020-05-15 09:02:58 -05:00
Rick Carlino ee517b2f9b v10.0.0-rc28 - Add Process.sleep, lower DirtyWorker polling interval 2020-05-14 17:22:25 -05:00
Rick Carlino b9fca35731 v10.0.0-rc27 - Thanks, Connor. 2020-05-14 16:17:37 -05:00
Rick Carlino 6d92a11ebd v10.0.0-rc26 2020-05-14 15:35:37 -05:00
Rick Carlino db1d6cf4f5 v10.0.0-rc25 - More debug points 2020-05-14 14:31:46 -05:00
Rick Carlino 6a07b8539f v10.0.0-rc24 - add loggers in `DiryWorker` module 2020-05-14 11:42:30 -05:00
Rick Carlino 10695dcc98 Store MARK AS failure logs 2020-05-13 15:43:59 -05:00
Rick Carlino 71e7c72329 Verbiage change HIGH/LOW => ON/OFF 2020-05-13 10:22:19 -05:00
Rick Carlino a64eb35ada Run logs when MARK AS fires 2020-05-12 17:52:02 -05:00
Rick Carlino 786fd450be Iterate over groups with the new MARK AS step 2020-05-12 11:48:33 -05:00
Rick Carlino 229aa645c9 v10.0.0-rc18 2020-05-11 13:44:50 -05:00
Rick Carlino 6ffbbe93d5 🎉 It works! 2020-05-11 13:37:29 -05:00
Rick Carlino 717a0d7544 [UNSTABLE] expected params to be a map with atoms or string keys, got a map with mixed keys 2020-05-11 11:34:40 -05:00
Rick Carlino 049411f272 TODO: Compile ASTs when pulling up vars in `better_params`. 2020-05-11 11:20:38 -05:00
Rick Carlino f0ea202196 [UNSTABLE] Fix pattern matches in do_update_resource 2020-05-11 10:59:36 -05:00
Rick Carlino 285fb1a491 Still debugging update_resource issues 2020-05-11 09:40:35 -05:00
Rick Carlino 4694108cfd Next idea: Replace `params` object with `better_params` object. Avoids legacy breakages 2020-05-09 16:35:16 -05:00
Rick Carlino 755cfb6f9e Dead code removal 2020-05-09 15:59:34 -05:00
Rick Carlino 4a31b34bf4 Inline stuff for now (debugging) 2020-05-09 14:37:24 -05:00
Rick Carlino 53a87744f3 WIP 2020-05-08 17:47:20 -05:00
Rick Carlino b820a40ac4 BUG FIX: Now possible to call MARK AS twice in the same sequence 2020-05-08 11:07:01 -05:00
Rick Carlino e1b3cec859 Revert changes to command.ex 2020-05-07 14:03:37 -05:00
Rick Carlino d99d93c0b9 Fix missing variable problem 2020-05-07 11:43:48 -05:00
Rick Carlino 0ccb44ff41 Update changlog, revert unneeded changes. 2020-05-06 19:13:34 -05:00
Rick Carlino 420c87601e Better error message when you try to MARK AS on coordinate (not possible) 2020-05-06 17:18:51 -05:00
Rick Carlino 06d9dcb69d Tool mounting from sequence editor works again 2020-05-06 11:57:48 -05:00
Rick Carlino 7a0978e2dd Remove excessive warnings 2020-05-06 11:42:54 -05:00
Rick Carlino de2233ccaf Merge conflict 2020-05-06 10:57:56 -05:00
Rick Carlino 4be016281d v10.0.0-rc15 ✔️ OTA issues 2020-05-05 16:47:08 -05:00
Rick Carlino 0b9dc6eafe 10.0.0-rc14 2020-05-05 16:04:03 -05:00
Rick Carlino 6cc44a07b0 Remove guard clause 2020-05-05 15:19:25 -05:00
Rick Carlino 007650df4a v10.0.0-rc13 2020-05-05 10:50:14 -05:00
Rick Carlino 323f853891 10.0.0-rc12 2020-05-04 17:28:53 -05:00
Rick Carlino 8d7fb9a010 v9.3.0-rc0 (debugging possible OTA system bug) 2020-05-04 16:58:30 -05:00
Rick Carlino b1c77657cd v10.0.0-rc11 - Fix typo in reset fn. 2020-05-04 14:18:36 -05:00
Rick Carlino bc3143465d v10.0.0-rc10 - Fix module / ENV errors. 2020-05-04 13:26:25 -05:00
Rick Carlino e023abd007 v10.0.0-rc9 2020-05-03 14:20:31 -05:00
Rick Carlino 0dd25156c7 v10.0.0-rc8 2020-05-03 13:56:15 -05:00
Rick Carlino 03555bf7eb v10.0.0-rc7 2020-05-03 13:21:06 -05:00
Rick Carlino 07a77c0d4b v10.0.0-rc6 2020-05-03 11:00:31 -05:00
Rick Carlino 18b5f3779b Ready for QA 2020-05-03 11:00:06 -05:00
Rick Carlino 471b9f2543 Remove references to old `reset` logic. TODO: Add new reset system based on `firmware_hardware` rather than platform 2020-05-03 09:07:30 -05:00
Rick Carlino 4a30a75cac Merge branch 'mark_as' into qa/10.0.0 2020-05-01 18:40:26 -05:00
Rick Carlino 38c0fcb5dc Verbiage 2020-05-01 18:34:09 -05:00
Rick Carlino 2469cb0168 v10.0.0-rc5 2020-05-01 15:47:47 -05:00
Rick Carlino 92dea8b0a1 === qa/v10.0.0-rc2 2020-05-01 14:53:57 -05:00
gabrielburnworth 13279262af [10.0.0-rc2] update arduino firmware (6.5.17) 2020-05-01 12:35:12 -07:00
Rick Carlino 20cf44ddad === qa/v10.0.0-rc1 2020-05-01 14:09:33 -05:00
Rick Carlino 3b66b164a7 Finish FarmbotCeleryScript.DotProps. TODO: Add `meta.*` attr support to `update_resource` RPC. 2020-04-30 21:44:26 -05:00
Rick Carlino e2696cd93b Begin `DotProps` helper to support metta attrs. 2020-04-30 15:10:34 -05:00
Rick Carlino 8b48613783 🎉 It updates points. TODO: `meta` attributes. 2020-04-30 14:37:56 -05:00
Rick Carlino 539f19c360 Add `reource_type` and `resource_id` to point lookup (required for variable MARK AS) 2020-04-30 14:07:21 -05:00
Rick Carlino 75bbeb7281 Continue MARK AS updates... 2020-04-29 20:44:31 -05:00
Rick Carlino 816da6128a TODO: test `update_resource` block that contains variables. 2020-04-28 17:43:55 -05:00
Rick Carlino c3f446d31f TODO: update FarmbotCeleryScript.SysCalls.update_resource/2 2020-04-28 14:43:17 -05:00
Rick Carlino c0670ec19a Merge branch 'recovery_release' into mark_as 2020-04-28 14:19:29 -05:00
Rick Carlino 4fab4bdbb6 Improve unit test naming 2020-04-28 14:15:45 -05:00
Rick Carlino ae8517b45d Format / merge 2020-04-28 14:09:57 -05:00
Rick Carlino dd3b5f2d40 Merge branch 'recovery_release' of github.com:FarmBot/farmbot_os into recovery_release 2020-04-28 14:09:32 -05:00
Rick Carlino 47d66b4701 Minor updates to criteria retriever 2020-04-28 14:09:16 -05:00
Rick Carlino 245bf3e0e6 Merge branch 'master' of github.com:FarmBot/farmbot_os into staging 2020-04-27 11:30:07 -05:00
Rick Carlino 968179322a WIP 2020-04-22 17:49:23 -05:00
Rick Carlino bce9f4385f Corpus update 2020-04-17 11:16:43 -05:00
Rick Carlino 856e19147e WIP 2020-04-17 10:33:51 -05:00
Rick Carlino c7653e14a0 Merge branch 'staging' of github.com:FarmBot/farmbot_os into recovery_release 2020-04-15 14:58:19 -05:00
Rick Carlino 0df4e78ba5
Merge branch 'staging' into recovery_release 2020-04-14 11:30:40 -05:00
Gabriel Burnworth 1bb175a387
Update FEATURE_MIN_VERSIONS.json [skip ci] 2020-04-13 15:54:51 -07:00
Rick Carlino fefd444aa0 Elock / unlock verbiage 2020-04-13 16:04:48 -05:00
Rick Carlino 8d70e8c454 Elock / unlock verbiage 2020-04-13 15:49:53 -05:00
Rick Carlino 643bbe8475 Yellow log when rebooting firmware. 2020-04-13 15:46:30 -05:00
Rick Carlino dac8fc7240 Friendlier movement errors during e-stop. 2020-04-13 15:44:08 -05:00
Rick Carlino ccd34f9943 Improve flash success message 2020-04-13 15:02:23 -05:00
Rick Carlino a57f44976b
Merge pull request #1197 from FarmBot/staging
Production release of v9.2.2
2020-04-13 14:20:02 -05:00
Rick Carlino 74291a7cc5
Merge pull request #1196 from FarmBot/final_rc
v9.2.2
2020-04-13 14:08:25 -05:00
Rick Carlino 37222d09d6 CI debug: Possible race condition, again? 2020-04-13 14:03:45 -05:00
Rick Carlino a55295f596 Force rebuild 2020-04-13 13:58:06 -05:00
Rick Carlino 8c4ee03193 v9.2.2 2020-04-13 13:51:42 -05:00
Rick Carlino 5eeebba6cf v9.2.2-rc22 - Possible fix for time-based criteria. 2020-04-13 12:26:52 -05:00
Rick Carlino 7ca2725540 v9.2.2-rc20 - Possible fix for time-based criteria. 2020-04-13 12:21:19 -05:00
Rick Carlino bfb4f21f54 v9.2.2-rc20 2020-04-13 11:48:40 -05:00
Rick Carlino 7407119942 v9.2.2-rc19 2020-04-13 10:40:17 -05:00
Rick Carlino b149504ca2 v9.2.2-rc18 2020-04-13 10:17:18 -05:00
Rick Carlino 92121b4955 v9.2.2-rc17 2020-04-12 19:42:57 -05:00
Rick Carlino 88da7a298c Formatting updates. 2020-04-12 17:39:34 -05:00
Rick Carlino 626fb4e5a4 Perform reset AFTER flash, not before. 2020-04-12 16:07:13 -05:00
Rick Carlino f463c698e0 Fix pullout_direction query issues 2020-04-12 12:47:10 -05:00
Rick Carlino 446aeb007d Add `pullout_direction` to points table 2020-04-12 12:33:37 -05:00
Rick Carlino 87fcc9f5a9 [UNSTABLE] Add new test cases to criteria retriever 2020-04-12 11:37:39 -05:00
Rick Carlino c9dc517df6 v9.2.2-rc14, manual override of errors. 2020-04-11 15:42:09 -05:00
Rick Carlino c82cd1f165 v9.2.2-rc13 2020-04-11 12:16:39 -05:00
Rick Carlino c9174cf1d2 v9.2.2-rc12 2020-04-11 11:39:47 -05:00
Rick Carlino 96867553e4 Add debug helpers 2020-04-11 11:17:19 -05:00
Rick Carlino 5eeec86db4 Remove VCR for clarity while debugging. 2020-04-11 10:43:50 -05:00
Rick Carlino 609150d96e v9.2.2-rc11 2020-04-10 21:01:23 -05:00
Rick Carlino 24d02d6a6c Add better logs 2020-04-10 20:56:47 -05:00
Rick Carlino e5a0c40389 v9.2.2-rc10 2020-04-10 20:21:41 -05:00
Rick Carlino a69decb139 v9.2.2-rc9 2020-04-10 19:19:23 -05:00
Rick Carlino 0fc39b1500 Remove guard clause from config.exs 2020-04-10 19:15:12 -05:00
Rick Carlino ebb9ff41e7 Better AVR Error handling 2020-04-10 16:16:18 -05:00
Rick Carlino c5e69e0c3d v9.2.2-rc8, plus dev doc updates 2020-04-10 10:13:13 -05:00
Rick Carlino fe2666e768
Merge pull request #1193 from FarmBot/qa/9.2.2-rc8
Qa/9.2.2 rc8
2020-04-10 10:05:53 -05:00
Rick Carlino 048e6db5fa v9.2.2-rc8 2020-04-10 09:37:39 -05:00
Rick Carlino 73a304da56 [UNSTABLE] Possible fix for runtime errors 2020-04-10 09:28:50 -05:00
Rick Carlino 992d9d4264 Update CHANGELOG for 9.2.2 2020-04-09 15:41:44 -05:00
Rick Carlino b3a2b49f49
Merge pull request #1191 from FarmBot/beta_rc
Beta RC
2020-04-09 11:39:41 -05:00
Rick Carlino abd6749434 Tests for FarmbotOS.Lua.Ext.FirmwareTest 2020-04-09 11:27:32 -05:00
Rick Carlino 726da83ed1 Begin tests for FarmbotOS.Lua.Ext.FirmwareTest 2020-04-09 10:47:14 -05:00
Rick Carlino 1749830a31 Fix misconfigured mock 2020-04-09 09:53:17 -05:00
Rick Carlino b6e2b83903 Revert GPIO changes 2020-04-09 09:21:14 -05:00
Rick Carlino 6e674d0e31 :none pullup mode again 2020-04-08 19:05:14 -05:00
Rick Carlino ebc371c4d0 :pullup pullup mode 2020-04-08 18:53:23 -05:00
Rick Carlino 298334aac5 :none pullup mode 2020-04-08 18:31:44 -05:00
Rick Carlino 5b5101313b Version bump 2020-04-08 18:21:08 -05:00
Rick Carlino 939afb52a4 Updates to firmware handler 2020-04-08 16:51:14 -05:00
Rick Carlino 0a7803e202 require FarmbotCore.Logger 2020-04-08 16:05:17 -05:00
Rick Carlino d091f52371 Bump VERSION 2020-04-08 16:01:03 -05:00
Rick Carlino 7d437d64f4 Add logger 2020-04-08 15:58:13 -05:00
Rick Carlino 427f317de0
Merge pull request #1190 from FarmBot/build_system_changes
Add "cheat sheet" section to docs
2020-04-07 09:48:30 -05:00
Rick Carlino d224d6ce7a
Merge branch 'staging' into build_system_changes 2020-04-07 09:39:23 -05:00
Rick Carlino 1469ab47ac Add note about local hex packages 2020-04-07 09:38:37 -05:00
Rick Carlino b477b74c37 Add "cheat sheet" section to docs 2020-04-07 09:34:16 -05:00
Rick Carlino 4c6d21d0a7
Merge pull request #1189 from FarmBot/build_system_changes
Dont configure NervesHub for dev use
2020-04-06 16:10:30 -05:00
Rick Carlino 5dfb9d3177 Dont configure NervesHub for dev use 2020-04-06 15:50:36 -05:00
Rick Carlino d513794868
Merge pull request #1188 from FarmBot/mon_tests
Test Maintenance, Dead Code Removal
2020-04-06 14:11:39 -05:00
Rick Carlino 7ea9e22c7d
Merge branch 'staging' into mon_tests 2020-04-06 14:06:47 -05:00
Rick Carlino d4e6ec2e20 Formatting 2020-04-06 14:05:10 -05:00
Rick Carlino 7293ea142b Tests and dead codde removal 2020-04-06 14:01:07 -05:00
Rick Carlino c2141cc835 Reduce noise in `farmbot_os` test suite 2020-04-06 12:39:33 -05:00
Rick Carlino a6b7305c3b
Merge pull request #1187 from FarmBot/mon_tests
Test Maintenance
2020-04-04 12:11:22 -05:00
Rick Carlino 4940fd88c7 [66.0%] param.ex tests 2020-04-04 12:06:06 -05:00
Rick Carlino a57ec7c08d [63.1%] Tests for `to_human` formatters, part I 2020-04-04 10:00:15 -05:00
Rick Carlino 11b00a7fa4 Reduce noisy logs. 2020-04-04 09:23:44 -05:00
Rick Carlino f8ff6db88d
Merge pull request #1186 from FarmBot/fri_tests
Routine Test Maintenance
2020-04-03 16:42:33 -05:00
Rick Carlino 878627f7c8 increase timeout 2020-04-03 16:38:15 -05:00
Rick Carlino 4138071c1a TODO: Fix blinky test, formatting. 2020-04-03 16:13:53 -05:00
Rick Carlino 7e4f133d96 Remove *.coverdata from source control 2020-04-03 16:01:03 -05:00
Rick Carlino c34aa56e17 [56.5%] Tests for factory.ex 2020-04-03 16:00:27 -05:00
Rick Carlino 52f0e6fba0 Begin doctests 2020-04-03 14:22:27 -05:00
Rick Carlino 19d42c5a25 Test suite log cleanup 3/3 2020-04-03 14:09:46 -05:00
Rick Carlino 161e97cf0a Test suite log cleanup 2/3 2020-04-03 14:04:36 -05:00
Rick Carlino e8caa769e3 Test suite log cleanup 1/3 2020-04-03 11:54:27 -05:00
Rick Carlino b93bd9c142 Merge branch 'staging' of github.com:FarmBot/farmbot_os into staging 2020-04-03 11:41:56 -05:00
Rick Carlino 4299721463
Merge pull request #1185 from FarmBot/thu_test_updates
farmbot_core test updates
2020-04-02 15:09:38 -05:00
Rick Carlino faf88bb925 Add note about blinky test in farmbot_ext (TODO) 2020-04-02 15:06:15 -05:00
Rick Carlino bb7831f1a1 Even more changes to account for differences between CI vs. dev 2020-04-02 15:00:10 -05:00
Rick Carlino 0f24ed894c Revert easy win that was not so easy 2020-04-02 14:55:11 -05:00
Rick Carlino fea135163e Minor tweak to LED tests 2020-04-02 14:49:28 -05:00
Rick Carlino 99ba1019a2 Test coverage for LEDs 2020-04-02 14:43:56 -05:00
Rick Carlino 63d03599dd Remove unused variables. Add tests for FarmbotCore.Project 2020-04-02 13:24:04 -05:00
Rick Carlino cadaea1e3a Dead code removal. 2020-04-02 13:05:36 -05:00
Rick Carlino e378c0c665 Reduce log noise in farmbot_core tests 2020-04-02 12:52:34 -05:00
Rick Carlino b3e4b58696 Remove test until SQLite issues can be fixed 2020-04-02 10:25:42 -05:00
Rick Carlino 10f90a9a91 TODO: Test on CI 2020-04-02 10:02:28 -05:00
Rick Carlino 680f208e97 Inline an unused fn 2020-04-01 12:40:13 -05:00
Rick Carlino bb4f910cfc [25.8%] Test for Asset.device/1 2020-04-01 11:38:36 -05:00
Rick Carlino 701141b0a3 [25.3%] Dead code removal 2020-04-01 11:19:54 -05:00
Rick Carlino 7108599645 Remove test entirely 2020-04-01 11:05:53 -05:00
Rick Carlino 09ae87e5b0 Comment out old / blinky test 2020-04-01 10:25:42 -05:00
Rick Carlino 1f7f250f48 Merge branch 'staging' of github.com:FarmBot/farmbot_os into tues_test_updates 2020-04-01 09:45:50 -05:00
Rick Carlino 477f9a8dd8 Merge branch 'staging' of github.com:FarmBot/farmbot_os into staging 2020-04-01 09:43:10 -05:00
Rick Carlino 681421e235 Merge branch 'master' of github.com:FarmBot/farmbot_os into staging 2020-04-01 09:31:21 -05:00
Rick Carlino 10b7c380b7 [UNSTABLE] Dont supervise anything in test env 2020-03-31 15:35:58 -05:00
Rick Carlino bcb0dae229
Merge pull request #1184 from FarmBot/tues_test_updates
Tues test updates
2020-03-31 15:00:37 -05:00
Rick Carlino 0c4b14eb1b mix format 2020-03-31 14:49:24 -05:00
Rick Carlino 53f28daefe Finish testing AutoSyncAssetHandler 2020-03-31 14:45:14 -05:00
Rick Carlino 1aac649e9b Test case: AutoSyncHnadler Handles @no_cache_kinds 2020-03-31 14:15:25 -05:00
Rick Carlino 78e44eeb81 Increase wait times to account for slowness of CI? 2020-03-31 11:53:18 -05:00
Rick Carlino 431e05284a [farmbot_ext: 12.1%] AutoSyncAssetHandler test for when auto_sync?() is enabled 2020-03-31 11:49:46 -05:00
Rick Carlino 04c74b28f2 Replace Process.sleep() with Helpers.wait_for(pid) 2020-03-31 11:37:23 -05:00
Rick Carlino e5a29361d2 👏 Race conditions arre gone from test suite 2020-03-31 11:09:56 -05:00
Rick Carlino aa6f3f4ad1 Race condition fix (probably) 2020-03-31 10:58:40 -05:00
Rick Carlino 06323242c2 Add Helpers.wait_for(pid). Remove :noop call 2020-03-31 10:36:48 -05:00
Rick Carlino ec62607648
Merge pull request #1183 from FarmBot/test_updates
Routine Test Updates
2020-03-31 09:43:30 -05:00
Rick Carlino 7fad9e7231 Formatting 2020-03-30 18:45:04 -05:00
Rick Carlino fe77262626 Coverage for FarmbotExt.API.ImageUploader 2020-03-30 18:38:41 -05:00
Rick Carlino 33b0947c7a Set `async` to `false` in a few missing places 2020-03-30 17:43:29 -05:00
Rick Carlino 9a5b927953 FarmbotExt: Dont supervise anything in :test 2020-03-26 17:06:55 -05:00
Rick Carlino 128ed8ec43 No supervisor children when in test env for FarmbotExt.Bootstrap.Supervisor 2020-03-26 16:30:02 -05:00
Rick Carlino e6b0f53224
Merge pull request #1178 from FarmBot/wed_ii
🛡️ Add codecov badge
2020-03-25 09:55:27 -05:00
Rick Carlino 63056be70b Update blinky test :-\ 2020-03-25 09:48:11 -05:00
Rick Carlino 442e6b1266 Add codecov badge 2020-03-25 09:43:49 -05:00
Rick Carlino 7e27e0e47a
Merge pull request #1177 from FarmBot/wed_ii
Revert previous commit
2020-03-25 09:41:05 -05:00
Rick Carlino 3ff10e0097 Revert previous commit 2020-03-25 09:37:04 -05:00
Rick Carlino 016b9cf9dd
Merge pull request #1176 from FarmBot/wed_ii
This will be reverted later.
2020-03-25 09:36:14 -05:00
Rick Carlino 742f2522cf This will be reverted later 2020-03-25 09:14:54 -05:00
Rick Carlino 54c9438f3f
Merge pull request #1175 from FarmBot/wed_ii
Remove old coverage task
2020-03-24 20:10:34 -05:00
Rick Carlino a9a519aee0 Remove report_coverage, actually. 2020-03-24 20:05:56 -05:00
Rick Carlino b6fc53634d Remove old coverage task 2020-03-24 19:57:47 -05:00
Rick Carlino 70d624c4c5
Merge pull request #1174 from FarmBot/wed_ii
Replace Coveralls with CodeCov
2020-03-24 19:55:56 -05:00
Rick Carlino a4dfb84b95 Test commit, please ignore 2020-03-24 19:50:17 -05:00
Rick Carlino 473c4904fc Better error message when ping/pong fails 2020-03-24 19:47:31 -05:00
Rick Carlino 1ab623a2b8
Merge pull request #1173 from FarmBot/staging
Publish v9.2.1
2020-03-24 14:25:49 -05:00
Rick Carlino cd1061e681
Merge pull request #1172 from FarmBot/qa/9.2.1
v9.2.1
2020-03-24 14:08:13 -05:00
Rick Carlino a5226b0bef v9.2.1 2020-03-24 13:52:57 -05:00
Rick Carlino 737559b215 Revert firmware changes (more QA required) 2020-03-24 09:20:43 -05:00
Rick Carlino 93d3b57178 9.2.1-rc12 2020-03-23 18:42:15 -05:00
Rick Carlino a1708dea8a Merge branch 'qa/9.2.1' of github.com:FarmBot/farmbot_os into qa/9.2.1 2020-03-23 18:19:58 -05:00
Rick Carlino aececd69f5 Make AVRDude errors more verbose 2020-03-23 18:19:10 -05:00
Rick Carlino 46064b802c Make AVRDude errors more verbose 2020-03-23 18:18:04 -05:00
Rick Carlino b396b47dc2 Minor update to OTA success log (was erroneously calling .error()) 2020-03-23 17:53:21 -05:00
Rick Carlino d5e10d7701 Add (1) / (2) to OTA error logs for better tracing 2020-03-23 17:27:16 -05:00
Rick Carlino 1a38833722 v9.2.1-rc9 2020-03-23 17:08:49 -05:00
Rick Carlino 7f190d2e44 v9.2.1-rc9 2020-03-23 17:08:24 -05:00
Rick Carlino 6e3333c435 v9.2.1-rc9 2020-03-23 17:02:32 -05:00
Rick Carlino c44975414e 9.2.1-rc8 (empty release required for QA) 2020-03-23 16:51:07 -05:00
Rick Carlino 970c47a25d Use %Percent{}, not integer 2020-03-23 16:25:13 -05:00
Rick Carlino 58eef13d16 v9.2.1-rc6: Same as rc5, but I need an empty release to QA OTAs 2020-03-23 15:10:36 -05:00
Rick Carlino 5a85f840ac Format fixes, plus merge firmware updates 2020-03-23 14:28:07 -05:00
Rick Carlino f92b01f7f6 Merge branch 'qa/homing_updates' of github.com:FarmBot/farmbot_os into qa/9.2.1 2020-03-23 14:26:54 -05:00
Rick Carlino 2b7ea92275 v9.2.1-rc5 2020-03-23 14:22:49 -05:00
Rick Carlino a4b33c3a59 Possible fix for double OTA issues 2020-03-23 14:06:31 -05:00
gabrielburnworth c04f6e46f8 9.2.1-rc1 2020-03-23 10:15:35 -07:00
Rick Carlino 89842cd641 Update changlog 2020-03-19 16:50:48 -05:00
Rick Carlino 2cc245192d v9.2.1-rc4 2020-03-18 17:11:22 -05:00
Rick Carlino 6f7bd74abe Possible fix for "ERROR :ok" type messages 2020-03-18 11:39:47 -05:00
Rick Carlino bcbcb85f66 Merge branch 'staging' of github.com:FarmBot/farmbot_os into qa/9.2.1 2020-03-18 10:16:35 -05:00
Rick Carlino ba7e582e4a Make network success events a `success` log, not a `warning` 2020-03-14 16:05:23 -05:00
Rick Carlino e940b2c940 WIP. Moving firmware stuff into handlers. 2020-03-13 13:35:02 -05:00
Rick Carlino b26bf4f59f v9.2.1-rc2 2020-03-13 10:37:05 -05:00
Rick Carlino 8f39bf2b71 Add more log endpoints to debug estops 2020-03-13 09:50:45 -05:00
Rick Carlino ab09e31a0e
Merge pull request #1171 from FarmBot/express
Increase farmware time limit to 60s from 30s
2020-03-13 08:19:25 -05:00
Rick Carlino f23a632682 Update test case 2020-03-12 13:00:44 -05:00
Rick Carlino 59fb3fe50a Increase farmware time limit to 60s from 30s 2020-03-12 12:54:46 -05:00
Rick Carlino fe0ad9d914
Merge pull request #1169 from FarmBot/routine_unit_tests
Late addition unit test
2020-03-10 16:33:23 -05:00
Rick Carlino c903a0efc4 (8.2%) test handling of deleted assets when auto_sync is disabled 2020-03-10 16:15:57 -05:00
Rick Carlino 2f4b0a5754
Merge pull request #1168 from FarmBot/criteria_groups_cleanup
FarmbotExt Test Suite Cleanup
2020-03-10 15:47:58 -05:00
Rick Carlino 6440aacdb8 Formatting updates 2020-03-10 15:40:17 -05:00
Rick Carlino f8b36dd6a9 Lower coverage threshold :( 2020-03-10 15:35:00 -05:00
Rick Carlino e25a30a344 Test case: Autosync of a device asset. 2020-03-10 15:26:35 -05:00
Rick Carlino 9cd28db4b1 Prevent blinky tests for AutoSyncChannel 2020-03-10 13:06:29 -05:00
Rick Carlino 3b76ea17e8 simple tests: basic_cancel, basic_cancel_ok, basic_consume_ok 2020-03-10 12:40:52 -05:00
Rick Carlino 06926b05ce Dont start process tree in test env. Silence numerous logs. 2020-03-10 12:08:19 -05:00
Rick Carlino 9ff51f40d8 Merge branch 'staging' into criteria_groups_cleanup 2020-03-10 09:09:03 -05:00
Rick Carlino 14f988ec30 Merge branch 'staging' into criteria_groups_cleanup 2020-03-10 09:07:45 -05:00
Rick Carlino 94314f73a1
Merge pull request #1167 from FarmBot/rel-9.2.0
Rel 9.2.0
2020-03-09 20:09:23 -05:00
Rick Carlino 94e44a348d Release v9.2.0 2020-03-09 20:04:28 -05:00
Rick Carlino 655efccbc2
Merge pull request #1166 from FarmBot/qa/9.2.0-rc5
v9.2.0-rc5
2020-03-09 19:54:05 -05:00
Rick Carlino d409293211 Merge branch 'qa/9.2.0-rc5' of github.com:FarmBot/farmbot_os into qa/9.2.0-rc5 2020-03-09 14:06:48 -05:00
Rick Carlino 5f1e7e9171 Add missing parens. 2020-03-09 14:06:45 -05:00
Rick Carlino efa2bff829 WIP, need to prep an RC 2020-03-09 13:39:51 -05:00
gabrielburnworth bd06773726 9.2.0-rc5 2020-03-09 10:23:43 -07:00
Rick Carlino 1d85b95a48 Unit tests for AutoSyncChannel.terminate 2020-03-09 11:48:07 -05:00
Rick Carlino 5ef5bb7b91 Silence supervisor crash reports in test suite 2020-03-09 10:59:37 -05:00
Rick Carlino fb118002e4 WIP: TODO: Fix supervisor error messages in test suite 2020-03-09 09:30:55 -05:00
Rick Carlino 1f26485f88 Add `LOG_SILENCE` env for local dev, remove less helpful debug/warn logs (Elixir kind, not FarmBot kind) 2020-03-06 10:30:04 -06:00
Rick Carlino 0058d1b01e Update coveralls.json, tests for View.render/1 2020-03-05 15:41:54 -06:00
Rick Carlino 9216cf1456 ¯\_(ツ)_/¯ 2020-03-05 14:57:06 -06:00
Rick Carlino 9bdae98cad Merge branch 'coverage' into criteria_groups_cleanup 2020-03-04 15:18:53 -06:00
Rick Carlino 835e535e40 Doc updates and dead code removal 2020-03-04 15:14:48 -06:00
Rick Carlino 19bc0b120d Add coverage stats 2020-03-04 11:51:23 -06:00
Rick Carlino a7b476a601
Merge pull request #1164 from FarmBot/criteria_groups
Retrieve `point_ids` by the PointGroup's `criteria`
2020-03-04 11:09:34 -06:00
Rick Carlino 7de9dfe033 Formatting errors 2020-03-04 10:54:47 -06:00
Rick Carlino 4bd6a44afc format_float(nil), test updates 2020-03-04 10:50:18 -06:00
Rick Carlino 6b4290f77c Rever format_float changes (for now) 2020-03-03 15:24:16 -06:00
Rick Carlino ca54de1a7a Update format_float 2020-03-03 15:16:05 -06:00
Rick Carlino ee57987271 Possible bug fix 2020-03-03 15:14:08 -06:00
Rick Carlino e769a879b8 Formatting updates 2020-03-03 15:08:17 -06:00
Rick Carlino c1292c5c08 FAILING - Isolate bug seen on staging 2020-03-03 11:44:14 -06:00
Rick Carlino 519e5a3804 9.2.0-rc3 2020-03-03 10:18:10 -06:00
Rick Carlino 2b7bfb410d Merge branch 'master' of github.com:FarmBot/farmbot_os into qa/criteria_groups 2020-03-03 10:15:57 -06:00
Rick Carlino d518e8c891 9.2.0-rc3 QA Release 2020-03-03 10:15:30 -06:00
Rick Carlino bee7a0aaf9 Merge branch 'nil-positions' of github.com:FarmBot/farmbot_os into criteria_groups 2020-03-03 07:40:29 -06:00
Rick Carlino b85ab26b5e More test cases (spotted during QA) 2020-03-02 16:26:32 -06:00
Rick Carlino 037c2b3a27 Merge branch 'criteria_groups' of github.com:FarmBot/farmbot_os into criteria_groups 2020-03-02 15:29:18 -06:00
Rick Carlino ac0f929e2e Add mimic to farmbot_core 2020-03-02 15:29:11 -06:00
gabrielburnworth 28c2d66323 use nil instead of -1 for unknown positions 2020-03-02 07:50:25 -08:00
Rick Carlino f11e8fbc4b v9.2.0-rc2 2020-02-29 13:58:49 -06:00
Rick Carlino 5d0b11bb81 v9.2.0-rc1 2020-02-28 17:04:09 -06:00
Rick Carlino afec9d13bd Change name of syscall to find_points_via_group 2020-02-28 16:30:02 -06:00
Rick Carlino e06a53040f Revert changes to asset.ex 2020-02-28 15:08:26 -06:00
Rick Carlino 61d5673e37 And run `mix format` 2020-02-27 15:11:11 -06:00
Rick Carlino 5bab149008 Remove unused vars 2020-02-27 15:06:35 -06:00
Rick Carlino 22818d6c8f Possibly ready for QA? 2020-02-27 15:00:35 -06:00
Rick Carlino 0fab548533 Begin meta.* search 2020-02-27 12:30:11 -06:00
Rick Carlino 2a62a0bbeb More testing needed 2020-02-27 10:16:22 -06:00
Rick Carlino d991c6e558 More testing needed 2020-02-27 09:15:19 -06:00
Rick Carlino 4c9e054190 Minor cleanup 2020-02-26 20:42:44 -06:00
Rick Carlino 8e350f0a1b It works! 🎉 2020-02-26 20:37:41 -06:00
Rick Carlino 585fda2cc3 Merge conflicts 2020-02-26 20:22:51 -06:00
Rick Carlino f7a345e9bf PROBLEM: $positions are off-by-one 2020-02-26 20:19:40 -06:00
Rick Carlino 6a961390e6 Possible solution. Needs QA + tests 2020-02-26 19:39:41 -06:00
Rick Carlino 471269b7d5 Reduce code size of FarmbotCore.Asset.CriteriaRetriever 2020-02-25 16:47:48 -06:00
Rick Carlino d4d7cc020b ** (Sqlite.DbConnection.Error) near "?2": syntax error 2020-02-24 18:54:54 -06:00
Rick Carlino bf4c62ecbc TODO: map() actually needs to be a reduce() 2020-02-24 15:54:45 -06:00
Rick Carlino a8fa3044b5 TODO: Composable query 2020-02-24 14:50:57 -06:00
Rick Carlino fe4d64753f days => days_ago, make `*_eq` operations use `IN` rather than `=`. 2020-02-24 10:51:15 -06:00
Rick Carlino 0ad05f07d4 days => days_ago, make `*_eq` operations use `IN` rather than `=`. 2020-02-24 10:20:33 -06:00
Rick Carlino 3be4d58308 CriteriaRetriever.flatten/1 almost works 2020-02-21 19:18:26 -06:00
Rick Carlino 5fef363475 TODO: Implement PointGroupRetriever.flatten/1 2020-02-21 17:49:23 -06:00
Rick Carlino d0f09a1ee9 Add :criteria to view, changeset 2020-02-21 15:59:27 -06:00
Rick Carlino 987eaab83f Add default `criteria` 2020-02-21 15:44:19 -06:00
Rick Carlino 5f4e26cc58 Fix typo 2020-02-21 15:02:15 -06:00
Rick Carlino 6299407bc2 Add `criteria` column to PointGroup asset 2020-02-21 14:57:07 -06:00
Rick Carlino f43ab2c23d
Merge pull request #1162 from FarmBot/rel-9.1.2
v9.1.2 Release
2020-02-21 13:02:50 -06:00
Rick Carlino 9ebd6e2a73
Merge pull request #1161 from FarmBot/rel-9.1.2
v9.1.2
2020-02-21 12:53:24 -06:00
Rick Carlino 9e04ad0329 Release v9.1.2 2020-02-21 12:47:14 -06:00
Rick Carlino 41b38f7666 qa/9.1.2-rc6 2020-02-21 12:23:17 -06:00
Rick Carlino 25f8cc61a5 Merge branch 'fix-typo' of github.com:FarmBot/farmbot_os into qa/9.1.2-rc6 2020-02-21 12:21:10 -06:00
gabrielburnworth 36b84ee13d fix typo 2020-02-21 10:19:22 -08:00
Rick Carlino 121a6a52a2 Release v9.1.2 2020-02-20 18:54:42 -06:00
Rick Carlino f79842bbc9 Release v9.1.2 2020-02-20 18:50:01 -06:00
Rick Carlino ed20ceefc5
Merge pull request #1159 from FarmBot/qa/9.1.2-rc5
9.1.2 rc5
2020-02-20 16:07:52 -06:00
Rick Carlino 9d932c8025 v9.1.2-rc5 2020-02-20 15:46:29 -06:00
Rick Carlino 205fa6afd6 v9.1.2-rc4 2020-02-20 14:52:00 -06:00
Rick Carlino 91a57ef5af _underscore unused variables 2020-02-19 17:34:11 -06:00
Rick Carlino 2dc602c58c v9.1.2-rc3 2020-02-19 17:29:03 -06:00
Rick Carlino f066ff691a Formatting fixes, changelog, configurator fix 2020-02-19 17:23:24 -06:00
Rick Carlino 22a70d0c2c Merge branch 'error_codes' of github.com:FarmBot/farmbot_os into qa/9.1.2-rc 2020-02-19 17:20:26 -06:00
gabrielburnworth 42ff39376c update arduino firmware (6.5.9) 2020-02-19 15:17:59 -08:00
gabrielburnworth 694929f551 improve error reporting 2020-02-19 15:17:54 -08:00
gabrielburnworth 122efed214 fix typo 2020-02-19 14:59:08 -08:00
Rick Carlino 2c724e2a85 Merge branch 'staging' of github.com:FarmBot/farmbot_os into qa/9.1.2-rc1 2020-02-19 12:57:56 -06:00
Rick Carlino 153ab20362
Merge pull request #1158 from FarmBot/real_gantry_mounted_tools
Use device current_x when moving to a gantry mounted tool
2020-02-19 12:57:35 -06:00
Rick Carlino 8de41baa83 v9.1.2-rc1 2020-02-19 12:53:45 -06:00
Rick Carlino 7e3c252eeb Tests for gantry mounted tools 2020-02-19 12:42:25 -06:00
Rick Carlino ef78de66eb Merge conflicts 2020-02-19 12:26:15 -06:00
Rick Carlino 291a254059 Use Repo.query instead 2020-02-18 20:16:07 -06:00
Rick Carlino aac4244b90 Use raw SQL to prevent syntax errors in legacy migration 2020-02-18 20:11:40 -06:00
Rick Carlino 8eecadd06e
Merge pull request #1157 from FarmBot/verbiage_update
Very minor verbiage change to tool mounting logs
2020-02-18 20:00:56 -06:00
Rick Carlino e8814c2985 Very minor verbiage change to tool mounting logs 2020-02-18 19:52:02 -06:00
Rick Carlino 835c033850
Merge pull request #1156 from FarmBot/bug_fix_move_abs
Bug fix: Bad return value move_abs
2020-02-18 19:49:55 -06:00
Rick Carlino 4878c8fc36
Merge branch 'staging' into bug_fix_move_abs 2020-02-18 19:43:30 -06:00
Rick Carlino dfe6ff0fe4 Bug fix: Bad return value move_abs 2020-02-18 19:40:20 -06:00
Rick Carlino 26fdbe1502 Formatting fix 2020-02-18 18:39:00 -06:00
Rick Carlino 61d51a3a0c Merge branch 'real_gantry_mounted_tools' of github.com:FarmBot/farmbot_os into real_gantry_mounted_tools 2020-02-18 18:36:29 -06:00
Rick Carlino a56d381959 Possible implementation. Needs tests. 2020-02-18 18:35:57 -06:00
Rick Carlino a939c4f812 Possible implementation. Needs tests. 2020-02-18 18:33:17 -06:00
Rick Carlino 70a813317a
Merge pull request #1155 from FarmBot/week_8_ii
Test Updates
2020-02-18 15:40:06 -06:00
Rick Carlino 0b4d4e830c Increase coverage threshold 2020-02-18 15:19:31 -06:00
Rick Carlino 27a24d6413 Fix runtime error in test, part II 2020-02-18 14:30:23 -06:00
Rick Carlino 2cd5c936d4 Fix runtime error in test 2020-02-18 14:20:21 -06:00
Rick Carlino 7555ccd05e Restore FirmwareConfig after tests 2020-02-18 13:06:54 -06:00
Rick Carlino 0fed24eadb Asset related tests 2020-02-18 12:55:56 -06:00
Rick Carlino f5567494bb BoxLed tests 2020-02-18 12:08:15 -06:00
Rick Carlino e0068bd3c2
Merge pull request #1154 from FarmBot/firmware_fix
Test Updates, 18 Feb 20
2020-02-18 11:27:08 -06:00
Rick Carlino 314f510b0e Behaviour updates, II 2020-02-18 11:19:09 -06:00
Rick Carlino 585c1ff93f Behaviour updates 2020-02-18 11:06:13 -06:00
Rick Carlino 7d2d4aa216 63% - Firmware tests 2020-02-18 10:49:38 -06:00
Rick Carlino 23f668a321 Merge branch 'error_codes' of github.com:FarmBot/farmbot_os into firmware_fix 2020-02-17 18:03:02 -06:00
Rick Carlino d6b7ee774d === Begin testing new firmware fixes 2020-02-17 18:02:37 -06:00
Rick Carlino 24e573f72c
Merge pull request #1153 from FarmBot/week_8
More unit tests
2020-02-17 17:50:52 -06:00
Rick Carlino cf370f2e06 (45.1%) set io mode tests 2020-02-17 17:42:09 -06:00
Rick Carlino de0953b5bf (45.1%) Formatting fixes 2020-02-17 17:39:35 -06:00
gabrielburnworth 0e28da3f3a parse firmware error codes 2020-02-17 15:16:19 -08:00
Rick Carlino 6ad22199fb (44.9%) Tests for FarmbotOS.SysCalls.SendMessage 2020-02-17 16:41:32 -06:00
Rick Carlino 1cde334792 (44.4%) Finish tests FarmbotOS.SysCalls.ResourceUpdate 2020-02-17 16:26:06 -06:00
Rick Carlino 4918a75b62 (43.6%) Begin tests for FarmbotOS.SysCalls.ResourceUpdate 2020-02-17 16:03:08 -06:00
Rick Carlino 1c7e330cb5 (41.6%) Done testing PointLookup module 2020-02-17 15:33:20 -06:00
Rick Carlino 02c87a010e Merge branch 'week_8' of github.com:FarmBot/farmbot_os into week_8 2020-02-17 15:09:47 -06:00
Rick Carlino 4ae256d03b (41.0%) get_toolslot_for_tool tests 2020-02-17 13:28:10 -06:00
Rick Carlino 510575b596 (40.8%) PointLookup.point/2 2020-02-17 13:01:04 -06:00
Rick Carlino 7ec1b3069c (40.8%) PointLookup.point/2 2020-02-17 12:45:31 -06:00
Rick Carlino b59ece24fb (40.7%) PointLookup failure case tests 2020-02-17 12:13:44 -06:00
Rick Carlino c8536db446
Merge pull request #1152 from FarmBot/week_8_testing
Routine Test Updates
2020-02-17 12:00:47 -06:00
Rick Carlino 1dcff8e45a Merge branch 'week_8_testing' of github.com:FarmBot/farmbot_os into week_8_testing 2020-02-17 11:46:35 -06:00
Rick Carlino a9e03bcfce (39.9%) Formatting fixes 2020-02-17 11:33:24 -06:00
Rick Carlino 33b5c55146 (39.9%) Bump minimum coverage threshold 2020-02-17 11:32:54 -06:00
Rick Carlino cfc420cf8e (39.9%) Bump minimum coverage threshold 2020-02-17 10:50:52 -06:00
Rick Carlino 5d4a79b137 (39.9%) Edge case for `read_pin` 2020-02-17 10:28:11 -06:00
Rick Carlino 5a8df7234c (39.7%) read_pin with %Peripheral{} 2020-02-16 12:07:31 -06:00
Rick Carlino 78ea7d17c3 (39.0%) Tests for toggle_pin 2020-02-16 11:55:28 -06:00
Rick Carlino a842948d03 Merge branch 'staging' into week_8_testing 2020-02-14 13:58:54 -06:00
Rick Carlino 6269a57245
Merge pull request #1151 from FarmBot/rel-9.1.1
v9.1.1 Prod Release
2020-02-14 13:55:44 -06:00
Rick Carlino b4fd67aaad v9.1.1 2020-02-14 13:48:41 -06:00
Rick Carlino 53233d20b0
Merge pull request #1150 from FarmBot/qa/firmware_update
v9.1.1 - Arduino Firmware Updates
2020-02-14 13:42:16 -06:00
Rick Carlino da51b54bd9 (37.7%) Begin pin control tests 2020-02-14 11:55:03 -06:00
Rick Carlino 03da1dc96b (37.5%) Done testing movement.ex 2020-02-14 09:44:10 -06:00
Rick Carlino fbf9445f1e (36.3%) Done testing move_abs 2020-02-14 09:18:29 -06:00
gabrielburnworth 9ba78c07df [v9.1.1-rc3] update arduino firmware (6.5.8) 2020-02-13 16:22:07 -08:00
Rick Carlino 796ef547ef (36.2%%) Continue farmbot_os testing (movement.ex) 2020-02-13 16:15:21 -06:00
Rick Carlino a5c2c3c740 (34.4%) Continue farmbot_os testing (movement.ex) 2020-02-13 14:55:56 -06:00
Rick Carlino e98b17f2df (33.5%) Continue farmbot_os testing (movement.ex) 2020-02-13 14:37:46 -06:00
Rick Carlino 11b38b47db
Merge pull request #1149 from FarmBot/master
Master => staging
2020-02-12 21:03:08 -06:00
Rick Carlino 6ed34124e8
Merge pull request #1148 from FarmBot/rel-9.1.0
Release v9.1.0
2020-02-12 20:49:46 -06:00
Rick Carlino 6e033b0de8 Release v$(cat VERSION) 2020-02-12 20:44:44 -06:00
Rick Carlino 938f7fd04e
Merge pull request #1147 from FarmBot/qa/final_checks_9.1
Final checks, v9.1.0
2020-02-12 20:37:03 -06:00
Rick Carlino a916fbd51d v9.1.0-rc17 2020-02-12 20:20:42 -06:00
Gabriel Burnworth ef43e44625
remove ignored file 2020-02-12 18:03:56 -08:00
gabrielburnworth b91f3680ce update arduino firmware 2020-02-12 17:58:49 -08:00
Rick Carlino cb384e3323
Merge pull request #1146 from FarmBot/v9.1.0
v9.1.0, beta
2020-02-12 15:04:49 -06:00
Rick Carlino 49981ac9fb v9.1.0-rc16, the final version bump before `beta` promotion 2020-02-12 14:58:09 -06:00
Rick Carlino f457e320f8 v9.1.0-rc15, with migration 2020-02-12 14:49:52 -06:00
Rick Carlino d7c147257a v9.1.0-rc15 2020-02-12 13:48:22 -06:00
Rick Carlino 830dc25dbc Release v9.0.4-rc5 2020-02-12 11:01:27 -06:00
Rick Carlino 092d611ca8 v9.1.0-rc14 2020-02-12 10:13:12 -06:00
Rick Carlino 4cff9f3b97 Dynamic module loading "fix" 2020-02-12 10:09:07 -06:00
Rick Carlino e7aa6724ca Release v9.0.4-rc4 2020-02-12 09:15:22 -06:00
Rick Carlino db0e179512 Release v9.0.4-rc4 2020-02-12 08:41:24 -06:00
Rick Carlino b87a582579 v9.1.0-rc13 - Syntax error fix 2020-02-11 20:33:10 -06:00
Rick Carlino 16c2a5cd98 v9.1.0-rc12 - Syntax error fix 2020-02-11 20:26:49 -06:00
Rick Carlino b0da67b847 v9.1.0-rc11, minus typo 2020-02-11 20:07:02 -06:00
Rick Carlino 594b24553a v9.1.0-rc11 2020-02-11 19:58:26 -06:00
Rick Carlino cb37576908 v9.1.0-rc10 2020-02-11 19:38:04 -06:00
Rick Carlino 6e116243e9 Dont use `config` for setting reset fun; use Mimic instead 2020-02-11 19:33:37 -06:00
Rick Carlino 61a92ec25a Formatting fix 2020-02-11 16:25:32 -06:00
Rick Carlino 7dd311a840 Merge conflicts 2020-02-11 16:23:13 -06:00
Rick Carlino e696f7c895 Merge branch 'staging' of github.com:FarmBot/farmbot_os into week_8 2020-02-11 16:20:34 -06:00
Rick Carlino 5f93d6a03b v9.1.0-rc9 2020-02-11 16:18:22 -06:00
Rick Carlino fabd36fc80 Merge branch 'staging' of github.com:FarmBot/farmbot_os into qa/new_new_firmware 2020-02-11 16:13:45 -06:00
Rick Carlino e240e6b2f1
Merge pull request #1143 from jsimmonds2/bug/sluggish-farmware
Return rpc_ok with label from original RPC request
2020-02-11 16:10:21 -06:00
John Simmonds 6df0793e69
Merge branch 'staging' into bug/sluggish-farmware 2020-02-12 08:57:27 +11:00
Rick Carlino b5a5a6a41d Merge branch 'staging' of github.com:FarmBot/farmbot_os into qa/new_new_firmware 2020-02-11 15:07:41 -06:00
Rick Carlino 38ee343194 v9.1.0-rc8 2020-02-11 15:07:25 -06:00
Rick Carlino ff760cce70 Upgrade vintage_net 2020-02-11 15:04:31 -06:00
Rick Carlino 7a744677dc
Merge pull request #1144 from FarmBot/unit_updates
Step updates
2020-02-11 13:51:45 -06:00
Rick Carlino ea871f1563 Merge branch 'unit_updates' of github.com:FarmBot/farmbot_os into week_8 2020-02-11 11:30:42 -06:00
Rick Carlino d212710254 Merge branch 'staging' of github.com:FarmBot/farmbot_os into week_8 2020-02-11 11:30:34 -06:00
Rick Carlino 03d61d70c6 Merge branch 'unit_updates' of github.com:FarmBot/farmbot_os into qa/new_new_firmware 2020-02-11 11:16:06 -06:00
Rick Carlino ab5f3b33db 9.1.0-rc7 2020-02-11 08:17:08 -06:00
Rick Carlino 0747191a22 Clear EEPROM when user selects "none" firmware option. 2020-02-11 08:11:41 -06:00
Rick Carlino 3019782de6 v9.1.0-rc6 - Possible cleanup for `none` Firmware selection. 2020-02-11 07:49:40 -06:00
Rick Carlino 1bc2cbfe10 v9.1.0-rc5 2020-02-11 07:33:17 -06:00
John Simmonds 935a6acfc3
Return rpc_ok with label from original RPC request 2020-02-11 18:15:17 +11:00
gabrielburnworth 01e97de2a0 fix param units 2020-02-10 16:20:05 -08:00
Rick Carlino 132d737bc9 Version bump to v9.0.3-rc4 2020-02-10 18:03:31 -06:00
Rick Carlino 03874c0bfa
Merge pull request #1140 from FarmBot/week_8
Minor updates
2020-02-10 18:00:25 -06:00
Rick Carlino ba8c0caa3d Merge branch 'staging' of github.com:FarmBot/farmbot_os into week_8 2020-02-10 17:54:58 -06:00
Rick Carlino 2ab6911323
Merge branch 'staging' into week_8 2020-02-10 17:53:40 -06:00
Rick Carlino b7c9e3524b (31.6%) End Tests for Lua DataManipulation module 2020-02-10 17:22:24 -06:00
Rick Carlino 716004ee74 Tests for firmware_config related fns in Lua sandbox 2020-02-10 17:08:04 -06:00
Rick Carlino 340bbee970 Tests for `get_fbos_config` calls within lua sandbox 2020-02-10 17:00:57 -06:00
Rick Carlino cf8fccce52 Tests for `update_fbos_config` calls within lua sandbox 2020-02-10 16:45:39 -06:00
Rick Carlino b772e9d4fc Tests for `get_device` calls within lua sandbox 2020-02-10 16:29:06 -06:00
Rick Carlino 8e2626ce71 Begin Lua data manipulaltion tests 2020-02-10 16:13:55 -06:00
Rick Carlino 584071408a Debugging CI- hex is failing to install deps suddenly? 2020-02-10 14:48:24 -06:00
Rick Carlino 5f5517a276 v9.1.0-rc3 2020-02-10 14:24:57 -06:00
Rick Carlino 8429aa2331 WIP 2020-02-10 14:18:33 -06:00
Rick Carlino 1dee7fbfbe Tests for Lua related functionality 2020-02-10 12:48:04 -06:00
Rick Carlino 0478df98ea
Merge pull request #1139 from FarmBot/week_8
Feb 10 Updates
2020-02-10 11:29:33 -06:00
Rick Carlino 6fa5c5ad42 Merge branch 'remove-unused' of github.com:FarmBot/farmbot_os into week_8 2020-02-10 11:20:00 -06:00
Rick Carlino c2cbadb636 Remove unused vars 2020-02-10 11:19:02 -06:00
Rick Carlino f282f630b2 Merge branch 'test_coverage_updates' into week_8 2020-02-10 11:16:36 -06:00
Rick Carlino 8ae9335c53 Merge branch 'staging' of github.com:FarmBot/farmbot_os into test_coverage_updates 2020-02-10 11:16:16 -06:00
Rick Carlino 1a0d5732e9 Merge branch 'fix_990' into week_8 2020-02-10 11:15:18 -06:00
Rick Carlino b2fea77665 Merge branch 'staging' of github.com:FarmBot/farmbot_os into qa/week_7 2020-02-10 11:13:26 -06:00
Rick Carlino 8d657d832f Merge branch 'staging' of github.com:FarmBot/farmbot_os into qa/new_new_firmware 2020-02-10 11:05:41 -06:00
Rick Carlino a204c790ac Merge branch 'staging' of github.com:FarmBot/farmbot_os into fix_990 2020-02-10 11:02:50 -06:00
gabrielburnworth c56b4e0d6d remove unused firmware 2020-02-08 10:58:10 -08:00
Rick Carlino 4383f54c9a Remove warnings 2020-02-08 12:34:42 -06:00
Rick Carlino edd52563db Merge branch 'fix_990' into qa/new_new_firmware 2020-02-08 12:11:53 -06:00
Rick Carlino c4f1cc3aa5 Possible fix for #990 2020-02-08 12:11:05 -06:00
Rick Carlino 61efe7d97b
Merge pull request #1136 from FarmBot/ids
Support more descriptive board identifiers
2020-02-08 11:25:16 -06:00
gabrielburnworth f226fb3329 support more descriptive board identifiers 2020-02-07 16:13:37 -08:00
Rick Carlino 6686f7d60a v9.1.0-rc2 2020-02-07 10:06:48 -06:00
Rick Carlino a94af9d102 Update firmware submodule 2020-02-07 10:02:30 -06:00
Gabriel Burnworth ed32625f3d
change /_build dir location 2020-02-06 14:18:30 -08:00
Rick Carlino 5502218bd7 v9.0.4-rc2 2020-02-06 15:38:16 -06:00
Rick Carlino a4018a7763 First draft of IPv4 Static IP Fixes 2020-02-06 15:07:37 -06:00
Rick Carlino 5ef053aeec
Merge pull request #1135 from FarmBot/coverage_updates_week_7
`dump_info` removal, test coverage increases
2020-02-06 12:08:13 -06:00
Rick Carlino 56ccf70ad8 Remove 80 limit from root of project (CI is format checking build artifacts?) 2020-02-06 12:00:43 -06:00
Rick Carlino d598ab6280 Even more test ENV fixes 2020-02-06 11:53:58 -06:00
Rick Carlino 1c568f680a More ENV updates in farmbot_os tests 2020-02-06 10:12:34 -06:00
Rick Carlino 0b2cc362da Formatting fix 2020-02-06 10:06:58 -06:00
Rick Carlino 783025eeca Un-hardcode reference to localhost in test 2020-02-06 10:05:08 -06:00
Rick Carlino 4faab5fe6a Corpus and formatting updates 2020-02-06 09:32:38 -06:00
Rick Carlino 1fce146504 Remove :telemetry_layer stuff now that Mimic is a thing 2020-02-05 15:38:52 -06:00
Rick Carlino c8e289409c Tests for /finish. TODO: Remove :telemetry_layer config references. 2020-02-05 15:27:23 -06:00
Rick Carlino a248d98f83 (27.3%) Tests for all but one configurator pages 2020-02-05 13:20:03 -06:00
Rick Carlino 5da2c58a44 Refactor some plug tests 2020-02-05 09:48:45 -06:00
Rick Carlino dbf6ba5739 Use =, not ==. 2020-02-04 14:22:39 -06:00
Rick Carlino 2938d74927 Merge branch 'remove_diag_dumps' into test_coverage_iii 2020-02-04 14:17:58 -06:00
Rick Carlino 3e34d158fd Merge branch 'staging' of github.com:FarmBot/farmbot_os into farmbot_os_testing 2020-02-04 14:13:03 -06:00
Rick Carlino f0b0ff10b0 Remove diag dumps 2020-02-04 14:11:17 -06:00
Rick Carlino f7410c3a5c Remove unfinished test 2020-02-04 13:58:19 -06:00
Rick Carlino e99e590cb5 WIP 2020-02-04 13:47:07 -06:00
Rick Carlino 024b239b80 (24.3%) Complete tests for ConfigDataLayer 2020-02-04 10:25:46 -06:00
Rick Carlino de7a874845 Remove :data_layer config (override via `Mimic` instead) 2020-02-04 10:13:59 -06:00
Rick Carlino 74788346c7 ConfigDataLayer.save_config tests 2020-02-04 10:01:28 -06:00
Rick Carlino 06a18f3717 WIP 2020-02-04 09:51:24 -06:00
Rick Carlino c5357b990f begin ConfiguratorDataLayer testing 2020-02-04 09:30:09 -06:00
Rick Carlino 1fd1b2bbcb
Merge pull request #1134 from FarmBot/firmware_testing
Minor cleanup
2020-02-04 09:04:35 -06:00
Rick Carlino 020383a88b Remove MuonTrap adapters now that were using `Mimic` 2020-02-04 08:58:55 -06:00
Rick Carlino 1a07ad087c Minor cleanup 2020-02-04 08:45:45 -06:00
Rick Carlino e518122105
Merge pull request #1130 from FarmBot/firmware_testing
Test Updates
2020-02-04 08:31:32 -06:00
Rick Carlino 25f69665fb Remove unused vars 2020-02-04 08:11:02 -06:00
Rick Carlino 52056bc77d (56.8%) Done with farmbot_firmware testing for now- moving on to other sub apps 2020-02-04 08:05:44 -06:00
Rick Carlino a1b6b41a51 (53.1%) WIP - Param tests 2020-02-04 07:53:28 -06:00
Rick Carlino 5f86f1fe3c (52.6%) Param.to_human tests, part I 2020-02-03 19:02:28 -06:00
Rick Carlino 3007ec4509 (45.8%) Tests for lib/farmbot_firmware/package_utils.ex 2020-02-03 11:45:19 -06:00
Rick Carlino 28c631eb8f (45.7%) Most tests for FarmbotFirmware.PackageUtils 2020-02-03 11:35:53 -06:00
Rick Carlino 1bdb46bb68 (44.1%) Finished writing tests for FarmbotFirmware.GCODE.Encoder 2020-02-03 11:19:00 -06:00
Rick Carlino 795f7a326d (43.8%) command_movement_home tests 2020-02-03 11:01:33 -06:00
Rick Carlino 91b664f7df More do_encode tests 2020-02-03 10:54:49 -06:00
Rick Carlino dd8bfb5f3c More do_encode tests 2020-02-03 10:41:09 -06:00
Rick Carlino 97ce3d03a0 More GCode encoder tests 2020-01-31 15:46:44 -06:00
Rick Carlino dba657edc6 TEST (41.6%): report_position_change 2020-01-31 15:19:17 -06:00
Rick Carlino f67a4d2f4f TEST (41.0%): Decoder.decode_ints 2020-01-31 15:03:07 -06:00
Rick Carlino 986ac6884d TEST (40.5%): Decoder.decode_pv 2020-01-31 14:48:55 -06:00
Rick Carlino b36044662a TEST (40.1%): command() runs RPCs 2020-01-31 14:22:47 -06:00
Rick Carlino b5cad63a55 TEST: command() refuses to run RPCs in :boot state 2020-01-31 13:53:46 -06:00
Rick Carlino cd0a0a3a13 Move firwmare tests into appropriate file. 2020-01-31 13:32:06 -06:00
Rick Carlino b59075c9aa STABLE, 36.3% Firmware coverage. 2020-01-31 11:50:59 -06:00
Rick Carlino 80d353664b Doc comment update. 2020-01-30 11:13:43 -06:00
Rick Carlino a48e821f1f UNSTABLE. WIP. 2020-01-30 08:18:28 -06:00
Rick Carlino b8344763e8 Better error message for :transport_boot error. 2020-01-29 16:15:27 -06:00
Rick Carlino 6c270960b0 Use `@tag :skip` instead of commenting things out 2020-01-29 16:02:28 -06:00
Rick Carlino 16b7ab8af4 Use `@tag :skip` instead of commenting things out 2020-01-29 16:02:07 -06:00
Rick Carlino 3a788d86f7 (UNSTABLE) Possible repro case for the :transport_boot bug? 2020-01-29 14:49:10 -06:00
Rick Carlino a4c342f4cf (15.7%) Test cases for erroneous command()s 2020-01-29 13:58:35 -06:00
Rick Carlino fb93dac7cd (15.1%) Partial tests for lib/farmbot_firmware/command.ex 2020-01-29 13:24:28 -06:00
Rick Carlino 6fbc957b47 Formatting updates 2020-01-29 12:24:09 -06:00
Rick Carlino 9f95971b45 Merge branch 'revert_firmware' of github.com:FarmBot/farmbot_os into firmware_testing 2020-01-29 12:11:59 -06:00
gabrielburnworth fef3a3bf5c revert VCR removal 2020-01-29 09:53:46 -08:00
gabrielburnworth 404e49c31a revert firmware changes 2020-01-29 09:43:19 -08:00
Rick Carlino 990c7a6c13 Merge branch 'qa/arduino-firmware' into firmware_testing 2020-01-29 10:38:20 -06:00
Rick Carlino 0af92ff967 Merge conflicts 2020-01-29 10:38:04 -06:00
Rick Carlino 064e6d309b
Update README 2020-01-29 10:34:51 -06:00
Rick Carlino 54cb1dac13 Dead code removal. 2020-01-29 09:58:02 -06:00
Rick Carlino 1b8f10590f Test AVRDude edge cases 2020-01-29 09:43:08 -06:00
Rick Carlino 2a0e5aef6c Point users to the new releases page 2020-01-29 08:55:59 -06:00
Rick Carlino deb72cd177 GCode parser tests 2020-01-28 18:48:19 -06:00
Rick Carlino fc2831d58e Remove coverdata. 2020-01-28 16:53:43 -06:00
Rick Carlino a52ccb42b6 Remove unused VCR code 2020-01-28 15:06:52 -06:00
Rick Carlino aae4751568 Request.request_timeout tests 2020-01-28 12:54:05 -06:00
Rick Carlino 5bd80e29ca Update tests, formatting 2020-01-28 12:42:58 -06:00
Rick Carlino 12497e008d Merge branch 'qa/arduino-firmware' of github.com:FarmBot/farmbot_os into qa/arduino-firmware 2020-01-27 17:58:46 -06:00
Rick Carlino 3d61668446 Add warning about long running farmwares. 2020-01-27 17:57:48 -06:00
gabrielburnworth 7160c1f13a update arduino firmware version (6.5.0) 2020-01-27 13:19:24 -08:00
Rick Carlino a44448f86b Firmware updates, II 2020-01-27 15:12:28 -06:00
Rick Carlino c6f5c6270a Force re-sync when upgrading to 9.1.0 2020-01-27 14:42:33 -06:00
Rick Carlino e3d33a926a Very / changelog bump 2020-01-27 14:10:08 -06:00
Rick Carlino 8f69f00ffc Merge branch 'qa/arduino-firmware' of github.com:FarmBot/farmbot_os into qa/arduino-firmware 2020-01-27 14:00:30 -06:00
Rick Carlino 0b8d211e6b
Merge pull request #1127 from FarmBot/rel-9.0.3
v9.0.3
2020-01-27 12:57:14 -06:00
Rick Carlino f6c37e423b Release v9.0.3 2020-01-27 12:30:31 -06:00
Rick Carlino abb0e6696c Release v9.0.3-rc3 2020-01-27 09:29:55 -06:00
Rick Carlino 8a7e8e1096
Merge pull request #1126 from FarmBot/9.0.3-rc3
v9.0.3-rc3
2020-01-27 09:10:53 -06:00
Rick Carlino a2694185a7 v9.0.3-rc3 2020-01-27 09:03:14 -06:00
Rick Carlino 1620c422cc TODO: Debug cause of :transport firmware error. 2020-01-25 17:01:11 -06:00
Rick Carlino 2e8f66eeb4 Version bump to 9.0.3-rc2 2020-01-25 13:33:20 -06:00
Rick Carlino 7c5bbb7da7 Version bump to 9.0.3-rc1 2020-01-25 13:29:10 -06:00
Rick Carlino aed3b51be0
Merge pull request #1125 from FarmBot/friday
Test Updates and DI updates
2020-01-25 13:17:10 -06:00
Rick Carlino a0b5bff980 Disable failing test temporarily 2020-01-25 13:10:01 -06:00
Rick Carlino b83be2fda2 Fix typo 2020-01-25 13:04:26 -06:00
Rick Carlino 08aeed1cf5 2 failure => 1. 2020-01-25 12:31:36 -06:00
Rick Carlino c830099dd2 13 => 3 failures (:set_mimic_global) 2020-01-25 12:23:41 -06:00
Rick Carlino ee4606b03b Fix SysCalls.sync() tests 2020-01-25 12:13:02 -06:00
Rick Carlino 7059f3c44c FAILING: Verify mocks on exit. 2020-01-25 11:48:52 -06:00
Rick Carlino 407f7f5fee Coverage updates for UART adapter 2020-01-24 16:34:09 -06:00
gabrielburnworth e0765016d8 Update arduino-firmware 2020-01-24 13:39:36 -08:00
Rick Carlino 482c590b40
Merge pull request #1124 from FarmBot/mimic
Add Mimic, Test Coverage Updates
2020-01-24 09:55:15 -06:00
Rick Carlino 7812b761e9
Merge branch 'staging' into mimic 2020-01-24 09:49:47 -06:00
Rick Carlino e98ef0e88f Race condition fix :-/ 2020-01-24 09:42:47 -06:00
Rick Carlino 844d521537 FAILING, minor formatting / config issues 2020-01-24 09:36:56 -06:00
Rick Carlino e83ada7e93 fix farmbot_core formatting 2020-01-23 17:43:21 -06:00
Rick Carlino ff1576c171 fix farmbot_core tests 2020-01-23 17:40:17 -06:00
Rick Carlino 1e37e5cf5a Add Mimic to farmbot_core tests 2020-01-23 17:34:36 -06:00
Rick Carlino ce7af2155c [UNSTABLE] Remove hidden refs to TestSysCalls 2020-01-23 16:47:40 -06:00
Rick Carlino fc353c64d5 Formatting updates 2020-01-23 16:40:19 -06:00
Rick Carlino 3316baad82 Fix tests ✔️ 2020-01-23 16:31:43 -06:00
Rick Carlino ce4d3f1688 WIP: Fix FarmbotCeleryScriptTest 2020-01-23 16:21:09 -06:00
Rick Carlino d6ab57425b TODO: Fix FarmbotCeleryScript.SchedulerTest 2020-01-23 15:37:09 -06:00
Rick Carlino 9ba060c0f1 Fix set_servo_angle, get_sequence 2020-01-23 15:06:04 -06:00
Rick Carlino e1e8adfa00 Fix set_servo_angle, get_sequence 2020-01-23 15:02:15 -06:00
Rick Carlino f2790ff886 Fix read/write pin sys call tests 2020-01-23 14:46:23 -06:00
Rick Carlino e4af444ece TODO: Fix FarmbotCeleryScript.SysCallsTest. 50 tests, 11 failures 2020-01-22 21:03:46 -06:00
Rick Carlino 0c22021d66 TODO: Fix FarmbotCeleryScript.SysCallsTest. 49 tests, 13 failures 2020-01-22 20:51:48 -06:00
Rick Carlino ac7bf38be9 Fix SysCalls.point tests 2020-01-22 20:27:55 -06:00
Rick Carlino c9206ab484 TODO: Fix FarmbotCeleryScript.SysCallsTest. 47 tests, 16 failures 2020-01-22 19:56:29 -06:00
Rick Carlino 2c45bd3057 Fix FarmbotCeleryScript.CompilerGroupsTest 2020-01-22 19:23:23 -06:00
Rick Carlino 2f7685c077 Update FarmbotCeleryScriptTest to use Mimic 2020-01-22 17:07:22 -06:00
Rick Carlino f3f8316cc3 Dead code removal. 2020-01-22 16:23:13 -06:00
Rick Carlino 21a1201a06 Fix UART adapter code to interface with `mimic` 2020-01-22 13:35:13 -06:00
Rick Carlino 7b5b564204 FIX NETWORK_LAYER CONFIG STUFF 2020-01-22 13:23:50 -06:00
Rick Carlino feae00c8db TODO: FIX NETWORK_LAYER CONFIG STUFF 2020-01-22 12:40:42 -06:00
Rick Carlino 7e5738f883 [UNSTABLE] 42.1% Partial removal of :mox, some tests failing though 2020-01-22 11:41:43 -06:00
Rick Carlino 111541c4b3 tests for SysCall.emergency_lock() / emergency_unlock() 2020-01-22 09:44:54 -06:00
Rick Carlino 82028f7443 tests for SysCall.wait() 2020-01-22 09:39:15 -06:00
Rick Carlino 487fc9ca2e Tests for SysCall.named_pin 2020-01-22 09:34:22 -06:00
Rick Carlino 99b5f3436b 👏 Add `mimic` package to test suite 2020-01-22 09:21:05 -06:00
Rick Carlino a8741d6d6b
Merge pull request #1123 from FarmBot/update-readme
Bump up OS download links in README
2020-01-21 18:41:33 -06:00
Rory Aronson 413d35e299
Bump up OS download links in README 2020-01-21 13:57:26 -08:00
Rick Carlino 92fd788098
Merge pull request #1122 from FarmBot/reconciler_mock
More mocks.
2020-01-21 13:14:16 -06:00
Rick Carlino 596c3cc659 Typo 2020-01-21 13:08:52 -06:00
Rick Carlino cb6c83e368 Update formatting 2020-01-21 13:03:47 -06:00
Rick Carlino 66bc2cc3b0 Stub out reconciler usage in SysCall module 2020-01-21 11:55:36 -06:00
Rick Carlino 834efe05b3
Merge pull request #1120 from FarmBot/jan_20_tests
Test Additions
2020-01-21 09:39:29 -06:00
Rick Carlino 8e495409e3 Run formatter 2020-01-21 09:35:08 -06:00
Rick Carlino ebc5d89bda Update CI ENV vars 2020-01-21 09:31:19 -06:00
Rick Carlino fc24a780da Create `reconciler()` helper method in preparation for mock addition 2020-01-21 09:30:06 -06:00
Rick Carlino 72a5dfe688 Try codecov 2020-01-21 08:38:42 -06:00
Rick Carlino 5ef4f02193 SysCalls.get_sequence tests 2020-01-20 17:06:13 -06:00
Rick Carlino dca6fbbd33
Merge pull request #1116 from FarmBot/tests_for_groups
Test Updates.
2020-01-19 10:35:28 -06:00
Rick Carlino 5a449af74f Minor cleanup 2020-01-19 10:32:00 -06:00
Rick Carlino a2647f7fe2 (51.1%, STABLE). "good enough" tests for Sequence.sequnce/2 2020-01-19 10:28:37 -06:00
Rick Carlino cc1a97d886 (50.8%, STABLE). Needs better assertions 2020-01-19 09:19:08 -06:00
Rick Carlino eba61d34f8 (49.2%, FAILING) Move groups stuff into its own test for now. 2020-01-19 09:01:30 -06:00
Rick Carlino 88ace0db19 Simulate :get_point_group, remove dead code 2020-01-18 14:06:39 -06:00
Rick Carlino 4ce80f0431 WIP: Still failing 2020-01-17 18:01:28 -06:00
Rick Carlino ee010874f0 TODO: Fix failing test 2020-01-17 16:59:04 -06:00
Rick Carlino a8c4887841 Run mix format 2020-01-17 16:02:00 -06:00
Rick Carlino 26d31012fb Test: get_point_group test success case 2020-01-17 15:40:25 -06:00
Rick Carlino 12c55fb60f Test: PointGroup test failure case 2020-01-17 15:28:13 -06:00
Rick Carlino 1c00c543e3 Rename some test helpers 2020-01-17 13:42:58 -06:00
Rick Carlino 779c450545 Merge branch 'master' of github.com:FarmBot/farmbot_os into staging 2020-01-17 11:58:45 -06:00
Rick Carlino 7a6c544e21
Merge pull request #1115 from FarmBot/minor_friday_stuff
Minor updates before branch cleanup
2020-01-17 11:45:08 -06:00
Rick Carlino 5722bea421 Huge formatting update (sorry) 2020-01-17 09:58:53 -06:00
Rick Carlino a13e6c5832 Minor updates before branch cleanup 2020-01-17 09:53:15 -06:00
Rick Carlino 2d17b4e82f
Merge pull request #1113 from FarmBot/uart_tests
UART Updates
2020-01-13 19:47:16 -06:00
Rick Carlino a61c69c816 (9.1%) Test case: Error when re-attaching UART 2020-01-13 15:50:55 -06:00
Rick Carlino 010cf90348 test coverage @ 8.7%: FarmbotFirmware.UARTTransport resets UART on timeout 2020-01-13 15:39:23 -06:00
Rick Carlino 82f63dd0cc 8.3% coverage 2020-01-13 15:15:26 -06:00
Rick Carlino 4b92386534 Remove useless guard clause 2020-01-13 14:25:16 -06:00
Rick Carlino 0f24d4474b More tests: FarmbotFirmware.UARTTransport.{open, reset} 2020-01-13 14:19:59 -06:00
Rick Carlino 87398438b4 More tests: FarmbotFirmware.UARTTransport.{open, reset} 2020-01-13 14:11:15 -06:00
Rick Carlino 8d731d1590 Add UART Adapters to facilitate mocking 2020-01-13 09:29:25 -06:00
Gabriel Burnworth c5c8bb4428
Update RELEASE_NOTES.md (v9) [skip ci] 2020-01-10 04:35:26 -08:00
Rick Carlino 0cb0361e29
Merge pull request #1109 from FarmBot/rel-9.0.2
v9.0.1 - Jolly Juniper
2020-01-09 17:02:56 -06:00
Rick Carlino 5a95d6c30d
Merge pull request #1108 from FarmBot/rel-9.0.2
v9.0.2 - Jolly Juniper
2020-01-09 17:01:47 -06:00
Rick Carlino 82fc90c0ec Release v9.0.2 2020-01-09 16:58:39 -06:00
Rick Carlino 10ea92805f Release v9.0.1 2020-01-09 16:48:34 -06:00
Rick Carlino 6ad51907e6 Release v9.0.1 2020-01-09 16:44:36 -06:00
Rick Carlino 958d5c8f09 v9.0.1 2020-01-09 16:44:02 -06:00
Rick Carlino bd86cfe7a7 Release v9.0.1-rc3 2020-01-09 13:49:46 -06:00
Rick Carlino fd9886f23c
Merge pull request #1107 from FarmBot/qa/firmware_fixes_ii
v9.0.1-rc2
2020-01-09 13:38:07 -06:00
Rick Carlino 5c04f54cd8 v9.0.1-rc2 2020-01-09 13:32:45 -06:00
Rick Carlino 0d54937946 Pattern matching problems? 2020-01-09 11:59:02 -06:00
Rick Carlino d9ba9f25ca It appears that the `:reset` config is not passed in under all circumstances...? 2020-01-08 14:44:15 -06:00
Rick Carlino 2f640c5d13 If the process has already started, consider firmware reboot complete 2020-01-08 14:14:48 -06:00
Rick Carlino e2548b3af4 TEST RELEASE; PLEASE IGNORE. 2020-01-08 13:53:18 -06:00
Rick Carlino b33be76849
Merge pull request #1106 from FarmBot/muon_trap_tests
Test updates
2020-01-08 10:47:39 -06:00
Rick Carlino f7582e8922 Remove duplicate file 2020-01-08 10:42:14 -06:00
Rick Carlino 57cc8a8b37 Tests for AVRDude / MuonTrap usage 2020-01-08 10:37:53 -06:00
Rick Carlino 013d617538
Merge pull request #1102 from FarmBot/doc-updates
Elaborate on how firmware updates work
2019-12-31 13:29:22 -06:00
Connor Rigby 6fbb0c6ac8
Elaborate on how firmware updates work 2019-12-31 11:05:06 -08:00
285 changed files with 15068 additions and 17607 deletions

View File

@ -2,7 +2,7 @@ version: 2.0
defaults: &defaults
working_directory: /nerves/build
docker:
- image: nervesproject/nerves_system_br:latest
- image: nervesproject/nerves_system_br:1.11.3
install_elixir: &install_elixir
run:
@ -162,7 +162,9 @@ deploy_nerves_hub_firmware_steps: &deploy_nerves_hub_firmware_steps
- run:
name: Sign Image
working_directory: /nerves/build/farmbot_os
command: mix nerves_hub.firmware sign --key notreal /nerves/deploy/system/artifacts/farmbot-${MIX_TARGET}-$(cat ../VERSION).fw
command: |
mix deps.get
mix nerves_hub.firmware sign --key notreal /nerves/deploy/system/artifacts/farmbot-${MIX_TARGET}-$(cat ../VERSION).fw
- run:
name: Publish to NervesHub
working_directory: /nerves/build/farmbot_os
@ -199,12 +201,13 @@ jobs:
mix compile
mix format --check-formatted
mix coveralls.json
bash <(curl -s https://codecov.io/bash)
- save_cache:
key: v14-fbcs-test-dependency-cache-{{ checksum "farmbot_celery_script/mix.lock" }}
paths:
- farmbot_celery_script/_build/test
- farmbot_celery_script/deps
- save_cache:
- save_cache:
key: v14-fbcs-coverage-cache-{{ .Branch }}-{{ .Revision }}
paths:
- farmbot_celery_script/cover
@ -233,12 +236,13 @@ jobs:
mix compile
mix format --check-formatted
mix coveralls.json
bash <(curl -s https://codecov.io/bash)
- save_cache:
key: v14-fbfw-test-dependency-cache-{{ checksum "farmbot_firmware/mix.lock" }}
paths:
- farmbot_firmware/_build/test
- farmbot_firmware/deps
- save_cache:
- save_cache:
key: v14-fbfw-coverage-cache-{{ .Branch }}-{{ .Revision }}
paths:
- farmbot_firmware/cover
@ -277,13 +281,14 @@ jobs:
mix compile
mix format --check-formatted
mix coveralls.json --trace
bash <(curl -s https://codecov.io/bash)
- save_cache:
key: v14-fbcore-test-dependency-cache-{{ checksum "farmbot_core/mix.lock" }}
paths:
- farmbot_core/_build/test
- farmbot_core/deps
- farmbot_core/arduino
- save_cache:
- save_cache:
key: v14-fbcore-coverage-cache-{{ .Branch }}-{{ .Revision }}
paths:
- farmbot_core/cover
@ -325,12 +330,13 @@ jobs:
mix ecto.create
mix ecto.migrate
mix coveralls.json
bash <(curl -s https://codecov.io/bash)
- save_cache:
key: v14-fbext-test-dependency-cache-{{ checksum "farmbot_ext/mix.lock" }}
paths:
- farmbot_ext/_build/test
- farmbot_ext/deps
- save_cache:
- save_cache:
key: v14-fbext-coverage-cache-{{ .Branch }}-{{ .Revision }}
paths:
- farmbot_ext/cover
@ -348,7 +354,7 @@ jobs:
- checkout
- run: git submodule update --init --recursive
- restore_cache:
keys:
keys:
- v14-fbos-host-test-dependency-cache-{{ checksum "farmbot_os/mix.lock" }}
- <<: *install_elixir
- <<: *install_hex_archives
@ -360,69 +366,18 @@ jobs:
mix compile
mix format --check-formatted
mix coveralls.json
bash <(curl -s https://codecov.io/bash)
- save_cache:
key: v14-fbos-host-test-dependency-cache-{{ checksum "farmbot_os/mix.lock" }}
paths:
- farmbot_os/_build/host
- farmbot_os/deps/host
- save_cache:
- save_cache:
key: v14-fbos-coverage-cache-{{ .Branch }}-{{ .Revision }}
paths:
- farmbot_os/cover
- store_artifacts:
path: farmbot_os/cover
report_coverage:
<<: *defaults
environment:
MIX_ENV: test
MIX_TARGET: host
NERVES_LOG_DISABLE_PROGRESS_BAR: "yes"
ELIXIR_VERSION: 1.8.0
steps:
- checkout
- run: git submodule update --init --recursive
- <<: *install_elixir
- <<: *install_hex_archives
- <<: *install_mdl
- restore_cache:
keys:
- v14-fbsupport-test-dependency-cache-{{ checksum "mix.lock" }}
- restore_cache:
keys:
- v14-fbcs-coverage-cache-{{ .Branch }}-{{ .Revision }}
- restore_cache:
keys:
- v14-fbcs-coverage-cache-{{ .Branch }}-{{ .Revision }}
- restore_cache:
keys:
- v14-fbfw-coverage-cache-{{ .Branch }}-{{ .Revision }}
- restore_cache:
keys:
- v14-fbcore-coverage-cache-{{ .Branch }}-{{ .Revision }}
- restore_cache:
keys:
- v14-fbext-coverage-cache-{{ .Branch }}-{{ .Revision }}
- restore_cache:
keys:
- v14-fbos-coverage-cache-{{ .Branch }}-{{ .Revision }}
- run:
name: Check documentation formatting
command: |
mdl docs/
- run:
name: Report Coverage
working_directory: /nerves/build/
command: |
mix deps.get
mix compile
mix format --check-formatted
mix farmbot.coveralls circle
- save_cache:
key: v14-fbsupport-test-dependency-cache-{{ checksum "mix.lock" }}
paths:
- deps/
- _build
################################################################################
# target=rpi app_env=prod #
@ -717,22 +672,6 @@ workflows:
- beta
- next
- /^qa\/.*/
- report_coverage:
context: org-global
requires:
- test_farmbot_celery_script
- test_farmbot_firmware
- test_farmbot_core
- test_farmbot_ext
- test_farmbot_os
filters:
branches:
ignore:
- master
- staging
- beta
- next
- /^qa\/.*/
# master branch to staging.farmbot.io
nerves_hub_prod_stable_staging:

View File

@ -1,7 +1,77 @@
# Changelog
# 10.0.0
* Deprecate `resource_update` RPC
* Introduce `update_resource` RPC, which allows users to modify variables from the sequence editor.
* Genesis v1.5 and Express v1.0 firmware updates.
* Fix a bug where FBOS would not honor an "AUTO UPDATE" value of "false".
# 9.2.2
* Fix firmware locking error ("Can't perform X in Y state")
* Removal of dead code / legacy plus numerous unit test additions.
* Added coveralls test coverage reporter
* Unit test additions (+2.7% coverage :tada:)
* Updates to build instructions for third party developers
* Bug fix for criteria-based groups that have only one filter criteria.
* Bug fix for express bots involving timeout during remote firmware flash
* Remove VCR again (for now)
* Increase farmware timeout to 20 minutes (use at own risk)
# 9.2.1
* Improve firmware debug messages.
* Remove confusing firmware debug messages, such as "Error OK".
* Improved camera support on FarmBot express.
* Bug fix to prevents OTA updates occuring when one is already in progress.
# 9.2.0
* Support for criteria-based groups.
* Genesis v1.5 and Express v1.0 firmware homing updates.
* Fix bug where unknown positions would report as -1.
# 9.1.2
* Genesis v1.5 and Express v1.0 firmware updates.
* Bug fix for movement error reporting
* Improved firmware error message reporting
* Improved support for gantry mounted tools.
# 9.1.1
* Genesis v1.5 and Express v1.0 firmware updates.
# 9.1.0
* Improved support for new FarmBot Express models
* Various firmware bug fixes for Express models.
* Bug fix for slow Farmware execution (Thanks, @jsimmonds2)
* Dependency upgrades
* Upgrade VintageNet (networking library)
* Removal of `dump_info` RPCs
* Numerous internal improvements, such as increasing test coverage and changing dependency injection scheme.
* Fix issue where firmware commands would be tried too many times.
# 9.0.4
* Bug fix for slow Farmware execution (Thanks, @jsimmonds2)
* Dependency upgrades
* Upgrade VintageNet (networking library)
* Removal of `dump_info` RPCs
* Numerous internal improvements, such as increasing test coverage and changing dependency injection scheme.
# 9.0.3
* Dependency updates
# 9.0.2
* See notes for 9.0.1.
# 9.0.1
* Routine token updates on Circle CI.
* Fix bugs that were causing devices to erroneously factory reset under some circumstances.
# 9.0.0
* Run updates on Nerves systems.

10
COVERAGE.md 100644
View File

@ -0,0 +1,10 @@
# Jan - Mar 2020
| Project | Jan 1 20 | Feb 6 20 | Mar 4 20 |STATUS|
|-----------------------|----------|----------|----------|------|
| farmbot_celery_script | 53.7% | 54.0% | 54.0% |OK |
| farmbot_core | 22.2% | 19.8% | 26.3% |OK |
| farmbot_ext | 53.6% | 52.7% | 38.1% |FIX | !!!
| farmbot_firmware | 13.8% | 56.4% | 62.0% |OK |
| farmbot_os | 22.0% | 27.6% | 45.3% |OK |
| farmbot_telemetry | ??.?% | ??.?% | ??.?% |LATER |

View File

@ -5,6 +5,7 @@
"assertion_block": "8.0.0",
"backscheduled_regimens": "6.4.0",
"change_ownership": "6.3.0",
"criteria_groups": "9.2.2",
"diagnostic_dumps": "6.4.4",
"endstop_invert": "6.4.1",
"express_k10": "8.0.0",
@ -20,6 +21,7 @@
"ota_update_hour": "8.2.3",
"rpi_led_control": "6.4.4",
"sensors": "6.3.0",
"update_resource": "10.0.0",
"use_update_channel": "6.4.12",
"variables": "8.0.0"
}

View File

@ -1,19 +1,17 @@
# Build status
| Master Build Status | Staging Build Status |
| :---: | :---: |
| [![Master Build Status](https://circleci.com/gh/FarmBot/farmbot_os/tree/master.svg?style=svg)](https://circleci.com/gh/FarmBot/farmbot_os/tree/master) | [![Staging Build Status](https://circleci.com/gh/FarmBot/farmbot_os/tree/staging.svg?style=svg)](https://circleci.com/gh/FarmBot/farmbot_os/tree/staging) |
---
<!-- DON'T CHANGE THE TEXT BELOW. It is used in documentation links. -->
# :floppy_disk: Latest OS Image Downloads
<!-- DON'T CHANGE THE TEXT ABOVE. It is used in documentation links. -->
Download the version of FarmBot OS that corresponds to the FarmBot kit and computer you have:
The FarmBot OS release page has moved to [my.farm.bot/os](https://my.farm.bot/os)
| FarmBot Kit | Computer | Download Link |
| --- | --- | --- |
| Genesis v1.2, Genesis v1.3, Genesis v1.4, Genesis XL v1.4 | Raspberry Pi 3 | [Download FBOS](https://github.com/FarmBot/farmbot_os/releases/download/v9.0.0/farmbot-rpi3-9.0.0.img) |
| Express v1.0, Express XL v1.0 | Raspberry Pi Zero W | Coming soon |
Old versions of FarmBot OS can be found [here](https://github.com/FarmBot/farmbot_os/releases). Please note that [FarmBot does not provide support for old versions of FBOS](https://software.farm.bot/docs/support-policy).
---
## Build status
| Master Build Status | Staging Build Status | Test Coverage |
| :---: | :---: | :---: |
| [![Master Build Status](https://circleci.com/gh/FarmBot/farmbot_os/tree/master.svg?style=svg)](https://circleci.com/gh/FarmBot/farmbot_os/tree/master) | [![Staging Build Status](https://circleci.com/gh/FarmBot/farmbot_os/tree/staging.svg?style=svg)](https://circleci.com/gh/FarmBot/farmbot_os/tree/staging) | [![codecov](https://codecov.io/gh/FarmBot/farmbot_os/branch/staging/graph/badge.svg)](https://codecov.io/gh/FarmBot/farmbot_os) |
---
@ -35,6 +33,8 @@ Installation should be fairly straight forward, you will need a computer for thi
1. download the [latest release file, available for download here](#floppy_disk-latest-os-image-downloads).
0. ```dd if=</path/to/file> of=/dev/<sddevice> bs=4``` or use [Etcher](https://etcher.io/).
---
## Running
_Refer to the [software documentation Configurator page](https://software.farm.bot/docs/configurator) for more detailed instructions._

View File

@ -24,3 +24,18 @@ This release uses an improved Farmware API:
* If you are a Farmware developer using Farmware Tools (`import farmware_tools`), the reinstalled Farmware should continue working as before. If you have authored a Farmware that does not use the package, you will need to replace any FarmBot device communication in your Farmware to use the `farmware_tools` package.
* See the [Farmware developer documentation](https://developer.farm.bot/docs/farmware) for more information.
# v9
FarmBot OS v8+ uses an improved Farmware API. See the [Farmware developer documentation](https://developer.farm.bot/docs/farmware) for more information.
# v10
FarmBot OS v10 features an improved *Mark As* step. If you have previously added *Mark As* steps to sequences, you will need to update them before they can be executed by FarmBot:
* Open any sequences with a caution icon next to the name.
* Click the `CONVERT` button in each old *Mark As* step.
* Save the sequence.
* If you have auto-sync disabled, press `SYNC NOW` once all sequences have been updated.
* Verify that any events using the updated sequences are running as expected.
FarmBot OS auto-update was disabled prior to this release.

View File

@ -1 +1 @@
9.0.1-rc1
10.0.0

View File

@ -6,6 +6,30 @@ This document will act as an index to available documentation.
* [FarmBot Source Code common terms](/docs/glossary.md)
## Cheat Sheet
**Create a *.fw file from local repo (RPi Zero):**
```sh
NERVES_SYSTEM=farmbot_system_rpi MIX_TARGET=rpi mix deps.get
NERVES_SYSTEM=farmbot_system_rpi MIX_TARGET=rpi mix firmware
sudo fwup farmbot_os/_build/rpi/rpi_dev/nerves/images/farmbot.fw
```
**Create a *.fw file from local repo (RPi v3):**
```sh
NERVES_SYSTEM=farmbot_system_rpi3 MIX_TARGET=rpi3 mix deps.get
NERVES_SYSTEM=farmbot_system_rpi3 MIX_TARGET=rpi3 mix firmware
sudo fwup farmbot_os/_build/rpi3/rpi3_dev/nerves/images/farmbot.fw
```
**Create or Update the Nerves System:**
Please see the official [Nerves documentation on "Nerves Systems"](https://hexdocs.pm/nerves/0.4.0/systems.html).
HINT: You may want to [develop the system locally](https://stackoverflow.com/a/28189056/1064917)
## Hardware specifics
Most FarmBot development/testing is done on a standard desktop PC.

View File

@ -10,7 +10,7 @@ Publishing a FarmBotOS release requires coordination of a few different systems.
## Legacy Release System
The legacy system is somewhat simpiler. It goes as follows:
The legacy system is somewhat simpler. It goes as follows:
### Pull request into `master` branch
@ -54,7 +54,7 @@ Beta releases are constructed by creating a tag off of the `staging` branch.
## NervesHub System
The NervesHub system is simpiler to use, but more complex to setup.
The NervesHub system is simpler to use, but more complex to setup.
### User registration

View File

@ -1,14 +1,69 @@
# Publishing OTAs
## Beta
## Beta OTA channel
Publish an OTA to the `beta` channel can be done by:
Beta updates are simply tags matching the following semver string:
```
vMajor.Minor.Tiny-rcRC
```
for example:
```
v10.5.6-rc30
```
To publish an OTA, just tag a release matching that
string.
```bash
cd $FARMBOT_OS_ROOT_DIRECTORY
git checkout staging
# Ensure you don't accidentally publish local changes
# that have not gone through CI:
git fetch --all
git reset --hard origin/staging
# update the CHANGELOG, but DO NOT put the `rc`
# on the semver string.
$EDITOR CHANGELOG.md
echo 1.2.3-rc4 > VERSION
git add -A
git commit -am "Release v10.5.6-rc30"
git tag v1.2.3-rc4
git push origin v1.2.3-rc4
```
or call the helper script:
`./scripts/release_candidate.sh`
### NOTE about release candidate script
the helper script only **increments** the
RC version. Calling the `release-candidate` script
from a non rc version will fail. Example:
This will fail:
```bash
$ cat VERSION
10.5.6
./scripts/release_candidate.sh
```
## QA
This will succeed:
```bash
$ cat VERSION
10.5.6-rc44
./scripts/release_candidate.sh
```
## QA OTA channel
Publish an OTA to the `qa` channel can be done by pushing a new branch
to github with `qa/` prefix.
@ -18,17 +73,27 @@ git checkout -b qa/<some-name>
git push origin qa/<some-name>
```
## Production
Publish an OTA to the `stable` channel can be done by:
or to build a QA image from an existing branch:
```bash
git checkout -b some-feature
git commit -am "build out some feature"
git push origin some-feature some-feature:qa/some-featuer
```
## Stable OTA channel
Publish an OTA to the `stable` OTA channel can be
done by pushing anything to the master branch:
```bash
git checkout -b rel-<version>
# update VERSION
echo $NEW_VERSION > VERSION
# update CHANGELOG.md
# update README.md
git commit -am "Release v<version>"
git push origin rel-<version>
$EDITOR CHANGELOG.md
git checkout -b rel-$(cat VERSION)
git commit -am 'Release v$(cat VERSION)'
git push origin rel-$(cat VERSION)
# open pull request
# merge pull request
# publish release once CI has completed

View File

@ -1,3 +1,4 @@
[
line_length: 80,
inputs: ["*.{ex,exs}", "{config,priv,lib,test}/**/*.{ex,exs}"]
]

View File

@ -25,3 +25,4 @@ farmbot_ng-*.tar
*.sqlite3
*.so
*.hex
*.coverdata

View File

@ -1,9 +1,4 @@
use Mix.Config
if Mix.env() == :test do
config :farmbot_celery_script, FarmbotCeleryScript.SysCalls,
sys_calls: Farmbot.TestSupport.CeleryScript.TestSysCalls
else
config :farmbot_celery_script, FarmbotCeleryScript.SysCalls,
sys_calls: FarmbotCeleryScript.SysCalls.Stubs
end
config :farmbot_celery_script, FarmbotCeleryScript.SysCalls,
sys_calls: FarmbotCeleryScript.SysCalls.Stubs

View File

@ -1,5 +1,7 @@
{
"skip_files": [
"lib/farmbot_celery_script/compiler/tools.ex"
]
],
"minimum_coverage": 53,
"treat_no_relevant_lines_as_covered": true
}

View File

@ -22,13 +22,14 @@
{
"name": "ALLOWED_MESSAGE_TYPES",
"allowed_values": [
"success",
"assertion",
"busy",
"warn",
"debug",
"error",
"info",
"fun",
"debug"
"info",
"success",
"warn"
]
},
{
@ -55,6 +56,15 @@
1
]
},
{
"name": "ALLOWED_ASSERTION_TYPES",
"allowed_values": [
"abort",
"recover",
"abort_recover",
"continue"
]
},
{
"name": "AllowedPinTypes",
"allowed_values": [
@ -89,10 +99,10 @@
"name": "LegalSequenceKind",
"allowed_values": [
"_if",
"assertion",
"calibrate",
"change_ownership",
"check_updates",
"dump_info",
"emergency_lock",
"emergency_unlock",
"execute",
@ -110,7 +120,6 @@
"read_status",
"reboot",
"remove_farmware",
"resource_update",
"send_message",
"set_servo_angle",
"set_user_env",
@ -118,6 +127,7 @@
"take_photo",
"toggle_pin",
"update_farmware",
"update_resource",
"wait",
"write_pin",
"zero"
@ -207,7 +217,8 @@
"planned",
"planted",
"harvested",
"sprouted"
"sprouted",
"removed"
]
},
{
@ -215,24 +226,18 @@
"allowed_values": [
"GenericPointer",
"ToolSlot",
"Plant"
"Plant",
"Weed"
]
},
{
"name": "resource_type",
"allowed_values": [
"Device",
"FarmEvent",
"Image",
"Log",
"Peripheral",
"Plant",
"Point",
"Regimen",
"Sequence",
"Tool",
"Plant",
"ToolSlot",
"User",
"Weed",
"GenericPointer"
]
},
@ -262,11 +267,13 @@
"z",
"pin_type",
"pointer_id",
"point_group_id",
"pointer_type",
"pin_mode",
"sequence_id",
"lhs",
"op",
"priority",
"channel_name",
"message_type",
"tool_id",
@ -274,19 +281,22 @@
"axis",
"message",
"speed",
"resource_type"
"resource_type",
"assertion_type",
"lua",
"resource"
]
},
{
"name": "LegalKindString",
"allowed_values": [
"Assertion",
"If",
"Calibrate",
"ChangeOwnership",
"Channel",
"CheckUpdates",
"Coordinate",
"DumpInfo",
"EmergencyLock",
"EmergencyUnlock",
"ExecuteScript",
@ -332,7 +342,10 @@
"MoveAbsolute",
"WritePin",
"ReadPin",
"ResourceUpdate"
"ResourceUpdate",
"Resource",
"UpdateResource",
"PointGroup"
]
}
],
@ -395,6 +408,10 @@
{
"tag": "identifier",
"name": "identifier"
},
{
"tag": "point_group",
"name": "point_group"
}
]
},
@ -626,6 +643,15 @@
}
]
},
{
"name": "point_group_id",
"allowed_values": [
{
"tag": "integer",
"name": "Integer"
}
]
},
{
"name": "pointer_type",
"allowed_values": [
@ -675,6 +701,15 @@
}
]
},
{
"name": "priority",
"allowed_values": [
{
"tag": "integer",
"name": "Integer"
}
]
},
{
"name": "channel_name",
"allowed_values": [
@ -746,9 +781,53 @@
"name": "resource_type"
}
]
},
{
"name": "assertion_type",
"allowed_values": [
{
"tag": "ALLOWED_ASSERTION_TYPES",
"name": "ALLOWED_ASSERTION_TYPES"
}
]
},
{
"name": "lua",
"allowed_values": [
{
"tag": "string",
"name": "String"
}
]
},
{
"name": "resource",
"allowed_values": [
{
"tag": "identifier",
"name": "identifier"
},
{
"tag": "resource",
"name": "resource"
}
]
}
],
"nodes": [
{
"allowed_args": [
"assertion_type",
"_then",
"lua"
],
"allowed_body_types": [],
"name": "assertion",
"tags": [
"*"
],
"docs": ""
},
{
"allowed_args": [
"lhs",
@ -832,18 +911,6 @@
],
"docs": ""
},
{
"allowed_args": [],
"allowed_body_types": [],
"name": "dump_info",
"tags": [
"function",
"network_user",
"disk_user",
"api_writer"
],
"docs": "Sends an info dump to server administrators for troubleshooting."
},
{
"allowed_args": [],
"allowed_body_types": [],
@ -1164,13 +1231,14 @@
},
{
"allowed_args": [
"label"
"label",
"priority"
],
"allowed_body_types": [
"assertion",
"calibrate",
"change_ownership",
"check_updates",
"dump_info",
"emergency_lock",
"emergency_unlock",
"execute",
@ -1189,7 +1257,7 @@
"read_status",
"reboot",
"remove_farmware",
"resource_update",
"update_resource",
"send_message",
"set_servo_angle",
"set_user_env",
@ -1239,10 +1307,10 @@
"locals"
],
"allowed_body_types": [
"assertion",
"calibrate",
"change_ownership",
"check_updates",
"dump_info",
"emergency_lock",
"emergency_unlock",
"execute",
@ -1261,7 +1329,7 @@
"read_status",
"reboot",
"remove_farmware",
"resource_update",
"update_resource",
"send_message",
"set_servo_angle",
"set_user_env",
@ -1474,6 +1542,45 @@
"network_user"
],
"docs": ""
},
{
"allowed_args": [
"resource_type",
"resource_id"
],
"allowed_body_types": [],
"name": "resource",
"tags": [
"network_user"
],
"docs": ""
},
{
"allowed_args": [
"resource"
],
"allowed_body_types": [
"pair"
],
"name": "update_resource",
"tags": [
"function",
"api_writer",
"network_user"
],
"docs": ""
},
{
"allowed_args": [
"point_group_id"
],
"allowed_body_types": [],
"name": "point_group",
"tags": [
"data",
"list_like"
],
"docs": ""
}
]
}
}

View File

@ -77,7 +77,8 @@ defmodule FarmbotCeleryScript.AST do
end
@spec new(atom, map, [map]) :: t()
def new(kind, args, body, comment \\ nil, meta \\ nil) when is_map(args) and is_list(body) do
def new(kind, args, body, comment \\ nil, meta \\ nil)
when is_map(args) and is_list(body) do
%AST{
kind: String.to_atom(to_string(kind)),
args: args,

View File

@ -5,10 +5,35 @@ defmodule FarmbotCeleryScript.AST.Factory do
alias FarmbotCeleryScript.AST
@doc """
Create an empty AST WITH ARG SET TO `nil`.
iex> new()
%FarmbotCeleryScript.AST{
args: nil,
body: [],
comment: nil,
kind: nil,
meta: nil
}
"""
def new do
%AST{body: []}
end
@doc """
Create a new AST to work with. Strings `kind`s are
converted to symbols.
iex> new("foo")
%FarmbotCeleryScript.AST{
args: %{},
body: [],
comment: nil,
kind: :foo,
meta: nil
}
"""
def new(kind, args \\ %{}, body \\ []) do
AST.new(kind, Map.new(args), body)
end
@ -19,65 +44,153 @@ defmodule FarmbotCeleryScript.AST.Factory do
def read_pin(%AST{} = ast, pin_number, pin_mode) do
ast
|> add_body_node(new(:read_pin, %{pin_number: pin_number, pin_mode: pin_mode}))
|> add_body_node(
new(:read_pin, %{pin_number: pin_number, pin_mode: pin_mode})
)
end
@doc """
iex> (new() |> rpc_request("x") |> set_pin_io_mode(13, 1)).body
[%FarmbotCeleryScript.AST{
kind: :set_pin_io_mode,
args: %{ pin_io_mode: 1, pin_number: 13 },
body: [],
comment: nil,
meta: nil
}]
"""
def set_pin_io_mode(%AST{} = ast, pin_number, pin_io_mode) do
ast
|> add_body_node(new(:set_pin_io_mode, %{pin_number: pin_number, pin_io_mode: pin_io_mode}))
end
def dump_info(%AST{} = ast) do
ast
|> add_body_node(new(:dump_info))
args = %{pin_number: pin_number, pin_io_mode: pin_io_mode}
ast |> add_body_node(new(:set_pin_io_mode, args))
end
@doc """
iex> (new() |> rpc_request("x") |> emergency_lock()).body
[%FarmbotCeleryScript.AST{
body: [],
comment: nil,
meta: nil,
args: %{},
kind: :emergency_lock
}]
"""
def emergency_lock(%AST{} = ast) do
ast
|> add_body_node(new(:emergency_lock))
ast |> add_body_node(new(:emergency_lock))
end
@doc """
iex> (new() |> rpc_request("x") |> emergency_unlock()).body
[%FarmbotCeleryScript.AST{
body: [],
comment: nil,
meta: nil,
args: %{},
kind: :emergency_unlock
}]
"""
def emergency_unlock(%AST{} = ast) do
ast
|> add_body_node(new(:emergency_unlock))
ast |> add_body_node(new(:emergency_unlock))
end
@doc """
iex> (new() |> rpc_request("x") |> read_status()).body
[%FarmbotCeleryScript.AST{
body: [],
comment: nil,
meta: nil,
args: %{},
kind: :read_status
}]
"""
def read_status(%AST{} = ast) do
ast
|> add_body_node(new(:read_status))
ast |> add_body_node(new(:read_status))
end
@doc """
iex> (new() |> rpc_request("x") |> power_off()).body
[%FarmbotCeleryScript.AST{
body: [],
comment: nil,
meta: nil,
args: %{},
kind: :power_off
}]
"""
def power_off(%AST{} = ast) do
ast
|> add_body_node(new(:power_off))
ast |> add_body_node(new(:power_off))
end
@doc """
iex> (new() |> rpc_request("x") |> reboot()).body
[%FarmbotCeleryScript.AST{
body: [],
comment: nil,
meta: nil,
args: %{},
kind: :reboot
}]
"""
def reboot(%AST{} = ast) do
ast
|> add_body_node(new(:reboot))
ast |> add_body_node(new(:reboot))
end
@doc """
iex> (new() |> rpc_request("x") |> sync()).body
[%FarmbotCeleryScript.AST{
body: [],
comment: nil,
meta: nil,
args: %{},
kind: :sync
}]
"""
def sync(%AST{} = ast) do
ast
|> add_body_node(new(:sync))
ast |> add_body_node(new(:sync))
end
@doc """
iex> (new() |> rpc_request("x") |> take_photo()).body
[%FarmbotCeleryScript.AST{
body: [],
comment: nil,
meta: nil,
args: %{},
kind: :take_photo
}]
"""
def take_photo(%AST{} = ast) do
ast
|> add_body_node(new(:take_photo))
ast |> add_body_node(new(:take_photo))
end
@doc """
iex> (new() |> rpc_request("x") |> flash_firmware("arduino")).body
[%FarmbotCeleryScript.AST{
kind: :flash_firmware,
comment: nil,
meta: nil,
args: %{package: "arduino"},
body: [],
}]
"""
def flash_firmware(%AST{} = ast, package) when is_binary(package) do
ast
|> add_body_node(new(:flash_firmware, %{package: package}))
ast |> add_body_node(new(:flash_firmware, %{package: package}))
end
@doc """
iex> (new() |> rpc_request("x") |> factory_reset("arduino")).body
[%FarmbotCeleryScript.AST{
kind: :factory_reset,
comment: nil,
meta: nil,
args: %{package: "arduino"},
body: [],
}]
"""
def factory_reset(%AST{} = ast, package) do
ast |> add_body_node(new(:factory_reset, %{package: package}))
end
def add_body_node(%AST{body: body} = ast, %AST{} = body_node) do
%{ast | body: body ++ [body_node]}
end
def factory_reset(%AST{} = ast, package) do
ast
|> add_body_node(new(:factory_reset, %{package: package}))
end
end

View File

@ -11,17 +11,10 @@ defmodule FarmbotCeleryScript.Compiler do
Compiler.IdentifierSanitizer
}
@doc "Sets debug mode for the compiler"
def debug_mode(bool \\ true) do
old = Application.get_env(:farmbot_celery_script, __MODULE__, [])
new = Keyword.put(old, :debug, bool)
Application.put_env(:farmbot_celery_script, __MODULE__, new)
bool
end
@doc "Returns current debug mode value"
def debug_mode?() do
Application.get_env(:farmbot_celery_script, __MODULE__)[:debug] || false
# Set this to `true` when debuging.
false
end
@valid_entry_points [:sequence, :rpc_request]
@ -94,27 +87,28 @@ defmodule FarmbotCeleryScript.Compiler do
defdelegate assertion(ast, env), to: Compiler.Assertion
defdelegate calibrate(ast, env), to: Compiler.AxisControl
defdelegate coordinate(ast, env), to: Compiler.DataControl
defdelegate execute(ast, env), to: Compiler.Execute
defdelegate execute_script(ast, env), to: Compiler.Farmware
defdelegate execute(ast, env), to: Compiler.Execute
defdelegate find_home(ast, env), to: Compiler.AxisControl
defdelegate home(ast, env), to: Compiler.AxisControl
defdelegate unquote(:_if)(ast, env), to: Compiler.If
defdelegate install_first_party_farmware(ast, env), to: Compiler.Farmware
defdelegate move_absolute(ast, env), to: Compiler.AxisControl
defdelegate move_relative(ast, env), to: Compiler.AxisControl
defdelegate named_pin(ast, env), to: Compiler.DataControl
defdelegate point(ast, env), to: Compiler.DataControl
defdelegate read_pin(ast, env), to: Compiler.PinControl
defdelegate resource_update(ast, env), to: Compiler.DataControl
defdelegate resource(ast, env), to: Compiler.DataControl
defdelegate rpc_request(ast, env), to: Compiler.RPCRequest
defdelegate sequence(ast, env), to: Compiler.Sequence
defdelegate set_pin_io_mode(ast, env), to: Compiler.PinControl
defdelegate set_servo_angle(ast, env), to: Compiler.PinControl
defdelegate set_user_env(ast, env), to: Compiler.Farmware
defdelegate take_photo(ast, env), to: Compiler.Farmware
defdelegate tool(ast, env), to: Compiler.DataControl
defdelegate toggle_pin(ast, env), to: Compiler.PinControl
defdelegate tool(ast, env), to: Compiler.DataControl
defdelegate unquote(:_if)(ast, env), to: Compiler.If
defdelegate update_farmware(ast, env), to: Compiler.Farmware
defdelegate update_resource(ast, env), to: Compiler.UpdateResource
defdelegate variable_declaration(ast, env), to: Compiler.VariableDeclaration
defdelegate write_pin(ast, env), to: Compiler.PinControl
defdelegate zero(ast, env), to: Compiler.AxisControl
@ -155,14 +149,20 @@ defmodule FarmbotCeleryScript.Compiler do
end
end
def send_message(%{args: %{message: msg, message_type: type}, body: channels}, env) do
def send_message(
%{args: %{message: msg, message_type: type}, body: channels},
env
) do
# body gets turned into a list of atoms.
# Example:
# [{kind: "channel", args: {channel_name: "email"}}]
# is turned into:
# [:email]
channels =
Enum.map(channels, fn %{kind: :channel, args: %{channel_name: channel_name}} ->
Enum.map(channels, fn %{
kind: :channel,
args: %{channel_name: channel_name}
} ->
String.to_atom(channel_name)
end)
@ -218,7 +218,9 @@ defmodule FarmbotCeleryScript.Compiler do
def flash_firmware(%{args: %{package: package_name}}, env) do
quote location: :keep do
FarmbotCeleryScript.SysCalls.flash_firmware(unquote(compile_ast(package_name, env)))
FarmbotCeleryScript.SysCalls.flash_firmware(
unquote(compile_ast(package_name, env))
)
end
end
@ -242,7 +244,9 @@ defmodule FarmbotCeleryScript.Compiler do
def factory_reset(%{args: %{package: package}}, env) do
quote location: :keep do
FarmbotCeleryScript.SysCalls.factory_reset(unquote(compile_ast(package, env)))
FarmbotCeleryScript.SysCalls.factory_reset(
unquote(compile_ast(package, env))
)
end
end
@ -269,20 +273,14 @@ defmodule FarmbotCeleryScript.Compiler do
end
end
def dump_info(_, _env) do
quote location: :keep do
FarmbotCeleryScript.SysCalls.dump_info()
end
end
defp print_compiled_code(compiled) do
IO.puts("========")
IO.puts("=== START ===")
compiled
|> Macro.to_string()
|> Code.format_string!()
|> IO.puts()
IO.puts("========\n\n")
IO.puts("=== END ===\n\n")
end
end

View File

@ -2,7 +2,7 @@ defmodule FarmbotCeleryScript.Compiler.IdentifierSanitizer do
@moduledoc """
Responsible for ensuring variable names in Sequences are clean.
This is done because identifiers are `unquote`d and the user controls
the data inside them. To prevent things like
the data inside them. To prevent things like
`"System.cmd("rm -rf /*/**")"` being evaluated, all identifiers
are sanitized by prepending a token and hashing the value.
"""

View File

@ -80,7 +80,8 @@ defmodule FarmbotCeleryScript.Compiler.Utils do
var =
quote location: :keep do
{unquote(next_scope_var_name), unquote(Compiler.compile_ast(data_value, env))}
{unquote(next_scope_var_name),
unquote(Compiler.compile_ast(data_value, env))}
end
compile_params_to_function_args(rest, env, [var | acc])
@ -117,12 +118,19 @@ defmodule FarmbotCeleryScript.Compiler.Utils do
parent = Keyword.get(params, :parent, %{x: 100, y: 200, z: 300})
"""
def compile_param_declaration(%{args: %{label: var_name, default_value: default}}, env) do
def compile_param_declaration(
%{args: %{label: var_name, default_value: default}},
env
) do
var_name = IdentifierSanitizer.to_variable(var_name)
quote location: :keep do
unquote({var_name, env, __MODULE__}) =
Keyword.get(params, unquote(var_name), unquote(Compiler.compile_ast(default, env)))
Keyword.get(
params,
unquote(var_name),
unquote(Compiler.compile_ast(default, env))
)
end
end
@ -152,11 +160,15 @@ defmodule FarmbotCeleryScript.Compiler.Utils do
]
}
"""
def compile_param_application(%{args: %{label: var_name, data_value: value}}, env) do
def compile_param_application(
%{args: %{label: var_name, data_value: value}},
env
) do
var_name = IdentifierSanitizer.to_variable(var_name)
quote location: :keep do
unquote({var_name, [], __MODULE__}) = unquote(Compiler.compile_ast(value, env))
unquote({var_name, [], __MODULE__}) =
unquote(Compiler.compile_ast(value, env))
end
end
@ -168,13 +180,16 @@ defmodule FarmbotCeleryScript.Compiler.Utils do
end)
end
def add_sequence_init_and_complete_logs(steps, sequence_name) when is_binary(sequence_name) do
def add_sequence_init_and_complete_logs(steps, sequence_name)
when is_binary(sequence_name) do
# This looks really weird because of the logs before and
# after the compiled steps
List.flatten([
quote do
fn ->
FarmbotCeleryScript.SysCalls.sequence_init_log("Starting #{unquote(sequence_name)}")
FarmbotCeleryScript.SysCalls.sequence_init_log(
"Starting #{unquote(sequence_name)}"
)
end
end,
steps,
@ -201,7 +216,9 @@ defmodule FarmbotCeleryScript.Compiler.Utils do
fn _ ->
[
fn ->
FarmbotCeleryScript.SysCalls.sequence_init_log("Starting #{unquote(sequence_name)}")
FarmbotCeleryScript.SysCalls.sequence_init_log(
"Starting #{unquote(sequence_name)}"
)
end
]
end

View File

@ -4,7 +4,11 @@ defmodule FarmbotCeleryScript.Compiler.Assertion do
@doc "`Assert` is a internal node useful for self testing."
def assertion(
%{
args: %{lua: expression, assertion_type: assertion_type, _then: then_ast},
args: %{
lua: expression,
assertion_type: assertion_type,
_then: then_ast
},
comment: comment
},
env
@ -80,7 +84,10 @@ defmodule FarmbotCeleryScript.Compiler.Assertion do
then_block ++
[
FarmbotCeleryScript.Compiler.compile(%AST{kind: :abort, args: %{}}, [])
FarmbotCeleryScript.Compiler.compile(
%AST{kind: :abort, args: %{}},
[]
)
]
end
end

View File

@ -1,12 +1,17 @@
defmodule FarmbotCeleryScript.Compiler.AxisControl do
alias FarmbotCeleryScript.Compiler
# Compiles move_absolute
def move_absolute(%{args: %{location: location, offset: offset, speed: speed}}, env) do
def move_absolute(
%{args: %{location: location, offset: offset, speed: speed}},
env
) do
quote location: :keep do
# Extract the location arg
with %{x: locx, y: locy, z: locz} = unquote(Compiler.compile_ast(location, env)),
with %{x: locx, y: locy, z: locz} =
unquote(Compiler.compile_ast(location, env)),
# Extract the offset arg
%{x: offx, y: offy, z: offz} = unquote(Compiler.compile_ast(offset, env)) do
%{x: offx, y: offy, z: offz} =
unquote(Compiler.compile_ast(offset, env)) do
# Subtract the location from offset.
# Note: list syntax here for readability.
[x, y, z] = [
@ -18,7 +23,11 @@ defmodule FarmbotCeleryScript.Compiler.AxisControl do
x_str = FarmbotCeleryScript.FormatUtil.format_float(x)
y_str = FarmbotCeleryScript.FormatUtil.format_float(y)
z_str = FarmbotCeleryScript.FormatUtil.format_float(z)
FarmbotCeleryScript.SysCalls.log("Moving to (#{x_str}, #{y_str}, #{z_str})", true)
FarmbotCeleryScript.SysCalls.log(
"Moving to (#{x_str}, #{y_str}, #{z_str})",
true
)
FarmbotCeleryScript.SysCalls.move_absolute(
x,
@ -36,9 +45,12 @@ defmodule FarmbotCeleryScript.Compiler.AxisControl do
with locx when is_number(locx) <- unquote(Compiler.compile_ast(x, env)),
locy when is_number(locy) <- unquote(Compiler.compile_ast(y, env)),
locz when is_number(locz) <- unquote(Compiler.compile_ast(z, env)),
curx when is_number(curx) <- FarmbotCeleryScript.SysCalls.get_current_x(),
cury when is_number(cury) <- FarmbotCeleryScript.SysCalls.get_current_y(),
curz when is_number(curz) <- FarmbotCeleryScript.SysCalls.get_current_z() do
curx when is_number(curx) <-
FarmbotCeleryScript.SysCalls.get_current_x(),
cury when is_number(cury) <-
FarmbotCeleryScript.SysCalls.get_current_y(),
curz when is_number(curz) <-
FarmbotCeleryScript.SysCalls.get_current_z() do
# Combine them
x = locx + curx
y = locy + cury
@ -77,8 +89,13 @@ defmodule FarmbotCeleryScript.Compiler.AxisControl do
# compiles find_home
def find_home(%{args: %{axis: axis}}, env) do
quote location: :keep do
with axis when axis in ["x", "y", "z"] <- unquote(Compiler.compile_ast(axis, env)) do
FarmbotCeleryScript.SysCalls.log("Finding home on the #{String.upcase(axis)} axis", true)
with axis when axis in ["x", "y", "z"] <-
unquote(Compiler.compile_ast(axis, env)) do
FarmbotCeleryScript.SysCalls.log(
"Finding home on the #{String.upcase(axis)} axis",
true
)
FarmbotCeleryScript.SysCalls.find_home(axis)
else
{:error, reason} ->
@ -92,7 +109,8 @@ defmodule FarmbotCeleryScript.Compiler.AxisControl do
quote location: :keep do
FarmbotCeleryScript.SysCalls.log("Going to home on all axes", true)
with speed when is_number(speed) <- unquote(Compiler.compile_ast(speed, env)),
with speed when is_number(speed) <-
unquote(Compiler.compile_ast(speed, env)),
:ok <- FarmbotCeleryScript.SysCalls.home("z", speed),
:ok <- FarmbotCeleryScript.SysCalls.home("y", speed) do
FarmbotCeleryScript.SysCalls.home("x", speed)
@ -103,9 +121,15 @@ defmodule FarmbotCeleryScript.Compiler.AxisControl do
# compiles home
def home(%{args: %{axis: axis, speed: speed}}, env) do
quote location: :keep do
with axis when axis in ["x", "y", "z"] <- unquote(Compiler.compile_ast(axis, env)),
speed when is_number(speed) <- unquote(Compiler.compile_ast(speed, env)) do
FarmbotCeleryScript.SysCalls.log("Going to home on the #{String.upcase(axis)} axis", true)
with axis when axis in ["x", "y", "z"] <-
unquote(Compiler.compile_ast(axis, env)),
speed when is_number(speed) <-
unquote(Compiler.compile_ast(speed, env)) do
FarmbotCeleryScript.SysCalls.log(
"Going to home on the #{String.upcase(axis)} axis",
true
)
FarmbotCeleryScript.SysCalls.home(axis, speed)
else
{:error, reason} ->
@ -129,8 +153,13 @@ defmodule FarmbotCeleryScript.Compiler.AxisControl do
# compiles zero
def zero(%{args: %{axis: axis}}, env) do
quote location: :keep do
with axis when axis in ["x", "y", "z"] <- unquote(Compiler.compile_ast(axis, env)) do
FarmbotCeleryScript.SysCalls.log("Zeroing the #{String.upcase(axis)} axis", true)
with axis when axis in ["x", "y", "z"] <-
unquote(Compiler.compile_ast(axis, env)) do
FarmbotCeleryScript.SysCalls.log(
"Zeroing the #{String.upcase(axis)} axis",
true
)
FarmbotCeleryScript.SysCalls.zero(axis)
else
{:error, reason} ->
@ -157,8 +186,13 @@ defmodule FarmbotCeleryScript.Compiler.AxisControl do
# compiles calibrate
def calibrate(%{args: %{axis: axis}}, env) do
quote location: :keep do
with axis when axis in ["x", "y", "z"] <- unquote(Compiler.compile_ast(axis, env)) do
FarmbotCeleryScript.SysCalls.log("Calibrating the #{String.upcase(axis)} axis", true)
with axis when axis in ["x", "y", "z"] <-
unquote(Compiler.compile_ast(axis, env)) do
FarmbotCeleryScript.SysCalls.log(
"Calibrating the #{String.upcase(axis)} axis",
true
)
FarmbotCeleryScript.SysCalls.calibrate(axis)
else
{:error, reason} ->

View File

@ -1,6 +1,19 @@
defmodule FarmbotCeleryScript.Compiler.DataControl do
alias FarmbotCeleryScript.Compiler
def resource(ast, _env) do
IO.puts("======")
IO.inspect(ast)
# %FarmbotCeleryScript.AST{
# args: %{resource_id: 0, resource_type: "Device"},
# body: [],
# comment: nil,
# kind: :resource,
# meta: nil
# }
raise "TODO: Pull resource from DB?"
end
# compiles coordinate
# Coordinate should return a vec3
def coordinate(%{args: %{x: x, y: y, z: z}}, env) do
@ -40,27 +53,4 @@ defmodule FarmbotCeleryScript.Compiler.DataControl do
)
end
end
def resource_update(
%{args: %{resource_type: kind, resource_id: id, label: label, value: value}, body: body},
env
) do
initial = %{label => value}
# Technically now body isn't supported by this node.
extra =
Map.new(body, fn %{args: %{label: label, data_value: value}} ->
{label, value}
end)
# Make sure the initial stuff higher most priority
params = Map.merge(extra, initial)
quote do
FarmbotCeleryScript.SysCalls.resource_update(
unquote(Compiler.compile_ast(kind, env)),
unquote(Compiler.compile_ast(id, env)),
unquote(Macro.escape(params))
)
end
end
end

View File

@ -13,7 +13,8 @@ defmodule FarmbotCeleryScript.Compiler.Execute do
loop_parameter_appl_ast =
Enum.find_value(parameter_applications, fn
# check if this parameter_application is a iterable type
%{kind: :parameter_application, args: %{data_value: %{kind: kind}}} = iterable
%{kind: :parameter_application, args: %{data_value: %{kind: kind}}} =
iterable
when kind in @iterables ->
iterable
@ -38,7 +39,10 @@ defmodule FarmbotCeleryScript.Compiler.Execute do
%FarmbotCeleryScript.AST{kind: :sequence} = celery_ast ->
celery_args =
celery_ast.args
|> Map.put(:sequence_name, celery_ast.args[:name] || celery_ast.meta[:sequence_name])
|> Map.put(
:sequence_name,
celery_ast.args[:name] || celery_ast.meta[:sequence_name]
)
|> Map.put(:locals, %{
celery_ast.args.locals
| body: celery_ast.args.locals.body ++ unquote(param_appls)
@ -53,13 +57,20 @@ defmodule FarmbotCeleryScript.Compiler.Execute do
end
end
def compile_execute(%{args: %{sequence_id: id}, body: parameter_applications}, env) do
def compile_execute(
%{args: %{sequence_id: id}, body: parameter_applications},
env
) do
quote location: :keep do
# We have to lookup the sequence by it's id.
case FarmbotCeleryScript.SysCalls.get_sequence(unquote(id)) do
%FarmbotCeleryScript.AST{} = ast ->
# compile the ast
env = unquote(compile_params_to_function_args(parameter_applications, env))
env =
unquote(
compile_params_to_function_args(parameter_applications, env)
)
FarmbotCeleryScript.Compiler.compile(ast, env)
error ->

View File

@ -30,7 +30,10 @@ defmodule FarmbotCeleryScript.Compiler.Farmware do
kvs =
Enum.map(pairs, fn %{kind: :pair, args: %{label: key, value: value}} ->
quote location: :keep do
FarmbotCeleryScript.SysCalls.set_user_env(unquote(key), unquote(value))
FarmbotCeleryScript.SysCalls.set_user_env(
unquote(key),
unquote(value)
)
end
end)

View File

@ -4,7 +4,15 @@ defmodule FarmbotCeleryScript.Compiler.If do
# Compiles an if statement.
def unquote(:_if)(
%{args: %{_then: then_ast, _else: else_ast, lhs: lhs_ast, op: op, rhs: rhs}},
%{
args: %{
_then: then_ast,
_else: else_ast,
lhs: lhs_ast,
op: op,
rhs: rhs
}
},
env
) do
rhs = Compiler.compile_ast(rhs, env)
@ -30,7 +38,10 @@ defmodule FarmbotCeleryScript.Compiler.If do
"pin" <> pin ->
quote [location: :keep],
do: FarmbotCeleryScript.SysCalls.read_cached_pin(unquote(String.to_integer(pin)))
do:
FarmbotCeleryScript.SysCalls.read_cached_pin(
unquote(String.to_integer(pin))
)
# Named pin has two intents here
# in this case we want to read the named pin.

View File

@ -1,7 +1,10 @@
defmodule FarmbotCeleryScript.Compiler.PinControl do
alias FarmbotCeleryScript.Compiler
# compiles write_pin
def write_pin(%{args: %{pin_number: num, pin_mode: mode, pin_value: value}}, env) do
def write_pin(
%{args: %{pin_number: num, pin_mode: mode, pin_value: value}},
env
) do
quote location: :keep do
pin = unquote(Compiler.compile_ast(num, env))
mode = unquote(Compiler.compile_ast(mode, env))
@ -23,7 +26,10 @@ defmodule FarmbotCeleryScript.Compiler.PinControl do
end
# compiles set_servo_angle
def set_servo_angle(%{args: %{pin_number: pin_number, pin_value: pin_value}}, env) do
def set_servo_angle(
%{args: %{pin_number: pin_number, pin_value: pin_value}},
env
) do
quote location: :keep do
pin = unquote(Compiler.compile_ast(pin_number, env))
angle = unquote(Compiler.compile_ast(pin_value, env))
@ -33,7 +39,10 @@ defmodule FarmbotCeleryScript.Compiler.PinControl do
end
# compiles set_pin_io_mode
def set_pin_io_mode(%{args: %{pin_number: pin_number, pin_io_mode: mode}}, env) do
def set_pin_io_mode(
%{args: %{pin_number: pin_number, pin_io_mode: mode}},
env
) do
quote location: :keep do
pin = unquote(Compiler.compile_ast(pin_number, env))
mode = unquote(Compiler.compile_ast(mode, env))

View File

@ -1,16 +1,18 @@
defmodule FarmbotCeleryScript.Compiler.Sequence do
import FarmbotCeleryScript.Compiler.Utils
alias FarmbotCeleryScript.Compiler.IdentifierSanitizer
@iterables [:point_group, :every_point]
def sequence(%{args: %{locals: %{body: params_or_iterables}}} = ast, env) do
# if there is an iterable AST here,
# if there is an iterable AST here,
# we need to compile _many_ sequences, not just one.
loop_parameter_appl_ast =
iterable_ast =
Enum.find_value(params_or_iterables, fn
# check if this parameter_application is a iterable type
%{kind: :parameter_application, args: %{data_value: %{kind: kind}}} = iterable
%{kind: :parameter_application, args: %{data_value: %{kind: kind}}} =
iterable
when kind in @iterables ->
iterable
@ -18,48 +20,42 @@ defmodule FarmbotCeleryScript.Compiler.Sequence do
false
end)
if loop_parameter_appl_ast,
do: compile_sequence_iterable(loop_parameter_appl_ast, ast, env),
else: compile_sequence(ast, env)
if iterable_ast do
compile_sequence_iterable(iterable_ast, ast, env)
else
compile_sequence(ast, env)
end
end
def compile_sequence_iterable(
loop_parameter_appl_ast,
%{args: %{locals: %{body: params} = locals} = sequence_args, meta: sequence_meta} =
sequence_ast,
iterable_ast,
%{
args: %{locals: %{body: _} = locals} = sequence_args,
meta: sequence_meta
} = sequence_ast,
env
) do
sequence_name = sequence_meta[:sequence_name] || sequence_args[:sequence_name]
# remove the iterable from the parameter applications,
# since it will be injected after this.
_params =
Enum.reduce(params, [], fn
# Remove point_group from parameter appls
%{kind: :parameter_application, args: %{data_value: %{kind: :point_group}}}, acc -> acc
# Remove every_point from parameter appls
%{kind: :parameter_application, args: %{data_value: %{kind: :every_point}}}, acc -> acc
# Everything else gets added back
ast, acc -> acc ++ [ast]
end)
sequence_name =
sequence_meta[:sequence_name] || sequence_args[:sequence_name]
# will be a point_group or every_point node
group_ast = loop_parameter_appl_ast.args.data_value
group_ast = iterable_ast.args.data_value
# check if it's a point_group first, then fall back to every_point
point_group_arg =
group_ast.args[:point_group_id] || group_ast.args[:resource_id] ||
group_ast.args[:every_point_type]
# lookup all point_groups related to this value
case FarmbotCeleryScript.SysCalls.get_point_group(point_group_arg) do
case FarmbotCeleryScript.SysCalls.find_points_via_group(point_group_arg) do
{:error, reason} ->
quote location: :keep, do: Macro.escape({:error, unquote(reason)})
%{name: group_name} = point_group ->
total = Enum.count(point_group.point_ids)
# Map over all the points returned by `get_point_group/1`
# Map over all the points returned by `find_points_via_group/1`
{body, _} =
Enum.reduce(point_group.point_ids, {[], 1}, fn point_id, {acc, index} ->
Enum.reduce(point_group.point_ids, {[], 1}, fn point_id,
{acc, index} ->
# check if it's an every_point node first, if not fall back go generic pointer
pointer_type = group_ast.args[:every_point_type] || "GenericPointer"
@ -67,7 +63,7 @@ defmodule FarmbotCeleryScript.Compiler.Sequence do
kind: :parameter_application,
args: %{
# inject the replacement with the same label
label: loop_parameter_appl_ast.args.label,
label: iterable_ast.args.label,
data_value: %FarmbotCeleryScript.AST{
kind: :point,
args: %{pointer_type: pointer_type, pointer_id: point_id}
@ -83,7 +79,10 @@ defmodule FarmbotCeleryScript.Compiler.Sequence do
%{name: name, x: x, y: y, z: z} ->
pos = FarmbotCeleryScript.FormatUtil.format_coord(x, y, z)
"unnamed iterable sequence [#{index} / #{total}] - #{name} #{pos}"
"unnamed iterable sequence [#{index} / #{total}] - #{name} #{
pos
}"
_ ->
"unknown iterable [#{index} / #{total}]"
@ -91,7 +90,7 @@ defmodule FarmbotCeleryScript.Compiler.Sequence do
# compile a `sequence` ast, injecting the appropriate `point` ast with
# the matching `label`
# TODO(Connor) - the body of this ast should have the
# TODO(Connor) - the body of this ast should have the
# params as sorted earlier. Figure out why this doesn't work
body =
compile_sequence(
@ -113,11 +112,48 @@ defmodule FarmbotCeleryScript.Compiler.Sequence do
end
end
def compile_sequence(%{args: %{locals: %{body: params}} = args, body: block, meta: meta}, env) do
def create_better_params(body, env) do
parameter_declarations =
Enum.reduce(env, %{}, fn
{key, value}, map ->
encoded_label = "#{key}"
if String.starts_with?(encoded_label, "unsafe_") do
Map.put(map, IdentifierSanitizer.to_string(encoded_label), value)
else
map
end
end)
Enum.reduce(body, parameter_declarations, fn ast, map ->
case ast do
%{kind: :parameter_application} ->
args = Map.fetch!(ast, :args)
label = Map.fetch!(args, :label)
Map.put(map, label, Map.fetch!(args, :data_value))
%{kind: :variable_declaration} ->
args = Map.fetch!(ast, :args)
label = Map.fetch!(args, :label)
Map.put(map, label, Map.fetch!(args, :data_value))
%{kind: :parameter_declaration} ->
map
end
end)
end
def compile_sequence(
%{args: %{locals: %{body: params}} = args, body: block, meta: meta},
env
) do
# Sort the args.body into two arrays.
# The `params` side gets turned into
# a keyword list. These `params` are passed in from a previous sequence.
# The `body` side declares variables in _this_ scope.
# === DON'T USE THIS IN NEW CODE.
# SCHEDULED FOR DEPRECATION.
# USE `better_params` INSTEAD.
{params_fetch, body} =
Enum.reduce(params, {[], []}, fn ast, {params, body} = _acc ->
case ast do
@ -141,6 +177,8 @@ defmodule FarmbotCeleryScript.Compiler.Sequence do
steps = add_sequence_init_and_complete_logs(steps, sequence_name)
better_params = create_better_params(params, env)
[
quote location: :keep do
fn params ->
@ -151,7 +189,7 @@ defmodule FarmbotCeleryScript.Compiler.Sequence do
# parent = Keyword.fetch!(params, :parent)
unquote_splicing(params_fetch)
unquote_splicing(assignments)
better_params = unquote(better_params)
# Unquote the remaining sequence steps.
unquote(steps)
end

View File

@ -0,0 +1,61 @@
defmodule FarmbotCeleryScript.Compiler.UpdateResource do
alias FarmbotCeleryScript.{AST, DotProps}
def update_resource(%AST{args: args, body: body}, _env) do
quote location: :keep do
me = unquote(__MODULE__)
variable = unquote(Map.fetch!(args, :resource))
update = unquote(unpair(body, %{}))
# Go easy on the API...
case variable do
%AST{kind: :identifier} ->
args = Map.fetch!(variable, :args)
label = Map.fetch!(args, :label)
resource = Map.fetch!(better_params, label)
me.do_update(resource, update)
%AST{kind: :point} ->
me.do_update(variable.args, update)
%AST{kind: :resource} ->
me.do_update(variable.args, update)
res ->
raise "Resource error. Please notfiy support: #{inspect(res)}"
end
end
end
def do_update(%{pointer_id: id, pointer_type: kind}, update_params) do
FarmbotCeleryScript.SysCalls.update_resource(kind, id, update_params)
end
def do_update(%{resource_id: id, resource_type: kind}, update_params) do
FarmbotCeleryScript.SysCalls.update_resource(kind, id, update_params)
end
def do_update(%{args: %{pointer_id: id, pointer_type: k}}, update_params) do
FarmbotCeleryScript.SysCalls.update_resource(k, id, update_params)
end
def do_update(other, update) do
raise String.trim("""
MARK AS can only be used to mark resources like plants and devices.
It cannot be used on things like coordinates.
Ensure that your sequences and farm events us MARK AS on plants and not
coordinates (#{inspect(other)} / #{inspect(update)})
""")
end
defp unpair([pair | rest], acc) do
key = Map.fetch!(pair.args, :label)
val = Map.fetch!(pair.args, :value)
next_acc = Map.merge(acc, DotProps.create(key, val))
unpair(rest, next_acc)
end
defp unpair([], acc) do
acc
end
end

View File

@ -2,7 +2,10 @@ defmodule FarmbotCeleryScript.Compiler.VariableDeclaration do
alias FarmbotCeleryScript.{Compiler, Compiler.IdentifierSanitizer}
@doc "Compiles a variable asignment"
def variable_declaration(%{args: %{label: var_name, data_value: data_value_ast}}, env) do
def variable_declaration(
%{args: %{label: var_name, data_value: data_value_ast}},
env
) do
# Compiles the `data_value`
# and assigns the result to a variable named `label`
# Example:
@ -26,7 +29,8 @@ defmodule FarmbotCeleryScript.Compiler.VariableDeclaration do
var_name = IdentifierSanitizer.to_variable(var_name)
quote location: :keep do
unquote({var_name, [], nil}) = unquote(Compiler.compile_ast(data_value_ast, env))
unquote({var_name, [], nil}) =
unquote(Compiler.compile_ast(data_value_ast, env))
end
end
end

View File

@ -18,14 +18,18 @@ defmodule FarmbotCeleryScript.Corpus do
@corpus_tag tag
# Load and decode each arg in the json into an Arg struct
@args Enum.map(args, fn %{"name" => name, "allowed_values" => allowed_values} = a ->
@args Enum.map(args, fn %{"name" => name, "allowed_values" => allowed_values} =
a ->
%Arg{name: name, allowed_values: allowed_values, doc: a["doc"]}
end)
# Load and decode each node in the json into a Node struct.
# This also expands the `allowed_args` into their respective Arg relationship.
@nodes Enum.map(@nodes, fn %{"name" => name, "allowed_args" => aa, "allowed_body_types" => abt} =
n ->
@nodes Enum.map(@nodes, fn %{
"name" => name,
"allowed_args" => aa,
"allowed_body_types" => abt
} = n ->
allowed_args =
Enum.map(aa, fn arg_name ->
Enum.find(@args, fn
@ -34,7 +38,12 @@ defmodule FarmbotCeleryScript.Corpus do
end) || Mix.raise("Unknown CeleryScript argument: #{arg_name}")
end)
%Node{name: name, allowed_args: allowed_args, allowed_body_types: abt, doc: n["doc"]}
%Node{
name: name,
allowed_args: allowed_args,
allowed_body_types: abt,
doc: n["doc"]
}
end)
# Struct should never be created manually.

View File

@ -0,0 +1,22 @@
defmodule FarmbotCeleryScript.DotProps do
@dot "."
@doc ~S"""
Takes a "dotted" key and val.
Returns deeply nested hash.
## Examples
iex> create("foo.bar.baz", 321)
%{"foo" => %{"bar" => %{"baz" => 321}}}
iex> create("foo", "bar")
%{"foo" => "bar"}
"""
def create(dotted, val) do
[key | list] = dotted |> String.split(@dot) |> Enum.reverse()
Enum.reduce(list, %{key => val}, fn next_key, acc ->
%{next_key => acc}
end)
end
end

View File

@ -1,4 +1,6 @@
defmodule FarmbotCeleryScript.FormatUtil do
def format_float(nil), do: nil
def format_float(value) when is_integer(value) do
format_float(value / 1)
end

View File

@ -67,7 +67,12 @@ defmodule FarmbotCeleryScript.Scheduler do
Calls are executed in a first in first out buffer, with things being added
by `execute/2` taking priority.
"""
@spec schedule(GenServer.server(), AST.t() | [Compiler.compiled()], DateTime.t(), map()) ::
@spec schedule(
GenServer.server(),
AST.t() | [Compiler.compiled()],
DateTime.t(),
map()
) ::
{:ok, reference()}
def schedule(scheduler_pid \\ __MODULE__, celery_script, at, data)
@ -147,12 +152,12 @@ defmodule FarmbotCeleryScript.Scheduler do
case DateTime.diff(DateTime.utc_now(), at, :millisecond) do
# now is before the next date
diff_ms when diff_ms < 0 ->
from_now =
DateTime.utc_now()
|> DateTime.add(abs(diff_ms), :millisecond)
|> Timex.from_now()
Logger.info("Next execution is still #{diff_ms}ms too early (#{from_now})")
# from_now =
# DateTime.utc_now()
# |> DateTime.add(abs(diff_ms), :millisecond)
# |> Timex.from_now()
# msg = "Next execution is still #{diff_ms}ms too early (#{from_now})"
# Logger.info(msg)
state
|> schedule_next_checkup(abs(diff_ms))
@ -160,8 +165,8 @@ defmodule FarmbotCeleryScript.Scheduler do
# now is more than the grace period past schedule time
diff_ms when diff_ms > @grace_period_ms ->
from_now = Timex.from_now(at)
Logger.info("Next execution is #{diff_ms}ms too late (#{from_now})")
# from_now = Timex.from_now(at)
# Logger.info("Next execution is #{diff_ms}ms too late (#{from_now})")
state
|> pop_next()
@ -171,7 +176,9 @@ defmodule FarmbotCeleryScript.Scheduler do
# now is late, but less than the grace period late
diff_ms when diff_ms >= 0 when diff_ms <= @grace_period_ms ->
Logger.info("Next execution is ready for execution: #{Timex.from_now(at)}")
Logger.info(
"Next execution is ready for execution: #{Timex.from_now(at)}"
)
state
|> execute_next()
@ -179,8 +186,15 @@ defmodule FarmbotCeleryScript.Scheduler do
end
end
def handle_info({:step_complete, {scheduled_at, executed_at, pid}, result}, state) do
send(pid, {FarmbotCeleryScript, {:scheduled_execution, scheduled_at, executed_at, result}})
def handle_info(
{:step_complete, {scheduled_at, executed_at, pid}, result},
state
) do
send(
pid,
{FarmbotCeleryScript,
{:scheduled_execution, scheduled_at, executed_at, result}}
)
state
|> pop_next()
@ -194,7 +208,9 @@ defmodule FarmbotCeleryScript.Scheduler do
scheduler_pid = self()
scheduled_pid =
spawn(fn -> StepRunner.step(scheduler_pid, {at, DateTime.utc_now(), pid}, compiled) end)
spawn(fn ->
StepRunner.step(scheduler_pid, {at, DateTime.utc_now(), pid}, compiled)
end)
%{state | scheduled_pid: scheduled_pid}
end
@ -291,7 +307,8 @@ defmodule FarmbotCeleryScript.Scheduler do
%{state | monitors: monitors}
end
@spec add(state(), compiled_ast(), DateTime.t(), data :: map(), pid()) :: state()
@spec add(state(), compiled_ast(), DateTime.t(), data :: map(), pid()) ::
state()
defp add(state, compiled, at, data, pid) do
%{state | compiled: [{compiled, at, data, pid} | state.compiled]}
|> index_next()

View File

@ -15,18 +15,20 @@ defmodule FarmbotCeleryScript.SysCalls do
@type error :: {:error, String.t()}
@type ok_or_error :: :ok | error
# "x", "y", or "z"
@type axis :: String.t()
@type package :: String.t()
@type resource_id :: integer()
@callback calibrate(axis) :: ok_or_error
@callback change_ownership(email :: String.t(), secret :: binary(), server :: String.t()) ::
@callback change_ownership(
email :: String.t(),
secret :: binary(),
server :: String.t()
) ::
ok_or_error
@callback check_update() :: ok_or_error
@callback coordinate(x :: number, y :: number, z :: number) ::
%{x: number(), y: number(), z: number()} | error
@callback dump_info() :: ok_or_error
@callback emergency_lock() :: ok_or_error
@callback emergency_unlock() :: ok_or_error
@callback execute_script(package, args :: map()) :: ok_or_error
@ -48,26 +50,37 @@ defmodule FarmbotCeleryScript.SysCalls do
%{x: number(), y: number(), z: number()} | error()
@callback home(axis, speed :: number()) :: ok_or_error
@callback install_first_party_farmware() :: ok_or_error
@callback move_absolute(x :: number(), y :: number(), z :: number(), speed :: number()) ::
@callback move_absolute(
x :: number(),
y :: number(),
z :: number(),
speed :: number()
) ::
ok_or_error
# ?
@callback named_pin(named_pin_type :: String.t(), resource_id) :: map() | integer | error()
@callback named_pin(named_pin_type :: String.t(), resource_id) ::
map() | integer | error()
@callback nothing() :: any()
@callback point(point_type :: String.t(), resource_id) :: number() | error()
@callback power_off() :: ok_or_error
@callback read_pin(pin_num :: number(), pin_mode :: number()) :: number | error()
@callback read_pin(pin_num :: number(), pin_mode :: number()) ::
number | error()
@callback read_cached_pin(pin_num :: number()) :: number | error()
@callback toggle_pin(pin_num :: number()) :: ok_or_error
@callback read_status() :: ok_or_error
@callback reboot() :: ok_or_error
@callback resource_update(String.t(), resource_id, map()) :: ok_or_error
@callback send_message(type :: String.t(), message :: String.t(), [atom]) :: ok_or_error
@callback send_message(type :: String.t(), message :: String.t(), [atom]) ::
ok_or_error
@callback set_servo_angle(pin :: number(), value :: number()) :: ok_or_error
@callback set_pin_io_mode(pin :: number(), mode :: number()) :: ok_or_error
@callback set_user_env(env_name :: String.t(), env_value :: String.t()) :: ok_or_error
@callback set_user_env(env_name :: String.t(), env_value :: String.t()) ::
ok_or_error
@callback sync() :: ok_or_error
@callback wait(millis :: number()) :: ok_or_error
@callback write_pin(pin_num :: number(), pin_mode :: number(), pin_value :: number) ::
@callback write_pin(
pin_num :: number(),
pin_mode :: number(),
pin_value :: number
) ::
ok_or_error
@callback zero(axis) :: ok_or_error
@ -77,10 +90,14 @@ defmodule FarmbotCeleryScript.SysCalls do
@callback eval_assertion(comment :: String.t(), expression :: String.t()) ::
true | false | error()
@callback get_point_group(String.t() | resource_id) :: %{required(:point_ids) => [resource_id]}
@callback find_points_via_group(String.t() | resource_id) :: %{
required(:point_ids) => [resource_id]
}
@callback update_resource(kind :: String.t(), resource_id, params :: map()) ::
ok_or_error
def get_point_group(sys_calls \\ @sys_calls, point_group_id) do
point_group_or_error(sys_calls, :get_point_group, [point_group_id])
def find_points_via_group(sys_calls \\ @sys_calls, point_group_id) do
point_group_or_error(sys_calls, :find_points_via_group, [point_group_id])
end
def format_lhs(sys_calls \\ @sys_calls, lhs)
@ -90,14 +107,18 @@ defmodule FarmbotCeleryScript.SysCalls do
def format_lhs(_sys_calls, "z"), do: "current z position"
def format_lhs(_sys_calls, "pin" <> num), do: "Pin #{num} value"
def format_lhs(sys_calls, %{kind: :named_pin, args: %{pin_type: type, pin_id: pin_id}}) do
def format_lhs(sys_calls, %{
kind: :named_pin,
args: %{pin_type: type, pin_id: pin_id}
}) do
case named_pin(sys_calls, type, pin_id) do
%{label: label} -> label
{:error, _reason} -> "unknown left hand side"
end
end
def eval_assertion(sys_calls \\ @sys_calls, comment, expression) when is_binary(expression) do
def eval_assertion(sys_calls \\ @sys_calls, comment, expression)
when is_binary(expression) do
case sys_calls.eval_assertion(comment, expression) do
true ->
true
@ -121,11 +142,13 @@ defmodule FarmbotCeleryScript.SysCalls do
apply(@sys_calls, :log, [message, force?])
end
def sequence_init_log(sys_calls \\ @sys_calls, message) when is_binary(message) do
def sequence_init_log(sys_calls \\ @sys_calls, message)
when is_binary(message) do
apply(sys_calls, :sequence_init_log, [message])
end
def sequence_complete_log(sys_calls \\ @sys_calls, message) when is_binary(message) do
def sequence_complete_log(sys_calls \\ @sys_calls, message)
when is_binary(message) do
apply(sys_calls, :sequence_complete_log, [message])
end
@ -148,10 +171,6 @@ defmodule FarmbotCeleryScript.SysCalls do
coord_or_error(sys_calls, :coordinate, [x, y, z])
end
def dump_info(sys_calls \\ @sys_calls) do
ok_or_error(sys_calls, :dump_info, [])
end
def emergency_lock(sys_calls \\ @sys_calls) do
ok_or_error(sys_calls, :emergency_lock, [])
end
@ -160,11 +179,13 @@ defmodule FarmbotCeleryScript.SysCalls do
ok_or_error(sys_calls, :emergency_unlock, [])
end
def execute_script(sys_calls \\ @sys_calls, package, %{} = env) when is_binary(package) do
def execute_script(sys_calls \\ @sys_calls, package, %{} = env)
when is_binary(package) do
ok_or_error(sys_calls, :execute_script, [package, env])
end
def update_farmware(sys_calls \\ @sys_calls, package) when is_binary(package) do
def update_farmware(sys_calls \\ @sys_calls, package)
when is_binary(package) do
ok_or_error(sys_calls, :update_farmware, [package])
end
@ -276,10 +297,6 @@ defmodule FarmbotCeleryScript.SysCalls do
ok_or_error(sys_calls, :reboot, [])
end
def resource_update(sys_calls \\ @sys_calls, kind, id, params) do
ok_or_error(sys_calls, :resource_update, [kind, id, params])
end
def send_message(sys_calls \\ @sys_calls, kind, msg, channels) do
ok_or_error(sys_calls, :send_message, [kind, msg, channels])
end
@ -312,6 +329,10 @@ defmodule FarmbotCeleryScript.SysCalls do
ok_or_error(sys_calls, :zero, [axis])
end
def update_resource(sys_calls \\ @sys_calls, kind, id, params) do
ok_or_error(sys_calls, :update_resource, [kind, id, params])
end
defp ok_or_error(sys_calls, fun, args) do
case apply(sys_calls, fun, args) do
:ok -> :ok
@ -336,8 +357,14 @@ defmodule FarmbotCeleryScript.SysCalls do
defp coord_or_error(sys_calls, fun, args) do
case apply(sys_calls, fun, args) do
%{x: x, y: y, z: z} = coord when is_number(x) when is_number(y) when is_number(z) -> coord
error -> or_error(sys_calls, fun, args, error)
%{x: x, y: y, z: z} = coord
when is_number(x)
when is_number(y)
when is_number(z) ->
coord
error ->
or_error(sys_calls, fun, args, error)
end
end
@ -348,7 +375,8 @@ defmodule FarmbotCeleryScript.SysCalls do
end
end
defp or_error(_sys_calls, _fun, _args, {:error, reason}) when is_binary(reason) do
defp or_error(_sys_calls, _fun, _args, {:error, reason})
when is_binary(reason) do
{:error, reason}
end

View File

@ -28,9 +28,6 @@ defmodule FarmbotCeleryScript.SysCalls.Stubs do
@impl true
def coordinate(x, y, z), do: error(:coordinate, [x, y, z])
@impl true
def dump_info(), do: error(:dump_info, [])
@impl true
def emergency_lock(), do: error(:emergency_lock, [])
@ -77,28 +74,32 @@ defmodule FarmbotCeleryScript.SysCalls.Stubs do
def get_sequence(resource_id), do: error(:get_sequence, [resource_id])
@impl true
def get_toolslot_for_tool(resource_id), do: error(:get_toolslot_for_tool, [resource_id])
def get_toolslot_for_tool(resource_id),
do: error(:get_toolslot_for_tool, [resource_id])
@impl true
def home(axis, speed), do: error(:home, [axis, speed])
@impl true
def install_first_party_farmware(), do: error(:install_first_party_farmware, [])
def install_first_party_farmware(),
do: error(:install_first_party_farmware, [])
@impl true
def move_absolute(x, y, z, speed), do: error(:move_absolute, [x, y, z, speed])
@impl true
def named_pin(named_pin_type, resource_id), do: error(:named_pin, [named_pin_type, resource_id])
def named_pin(named_pin_type, resource_id),
do: error(:named_pin, [named_pin_type, resource_id])
@impl true
def nothing(), do: error(:nothing, [])
@impl true
def point(point_type, resource_id), do: error(:point, [point_type, resource_id])
def point(point_type, resource_id),
do: error(:point, [point_type, resource_id])
@impl true
def get_point_group(id_or_type), do: error(:get_point_group, [id_or_type])
def find_points_via_group(id), do: error(:find_points_via_group, [id])
@impl true
def power_off(), do: error(:power_off, [])
@ -119,11 +120,8 @@ defmodule FarmbotCeleryScript.SysCalls.Stubs do
def reboot(), do: error(:reboot, [])
@impl true
def resource_update(kind, resource_id, data),
do: error(:resource_update, [kind, resource_id, data])
@impl true
def send_message(type, message, channels), do: error(:send_message, [type, message, channels])
def send_message(type, message, channels),
do: error(:send_message, [type, message, channels])
@impl true
def set_servo_angle(pin, value), do: error(:set_servo_angle, [pin, value])
@ -132,7 +130,8 @@ defmodule FarmbotCeleryScript.SysCalls.Stubs do
def set_pin_io_mode(pin, mode), do: error(:set_pin_io_mode, [pin, mode])
@impl true
def set_user_env(env_name, env_value), do: error(:set_user_env, [env_name, env_value])
def set_user_env(env_name, env_value),
do: error(:set_user_env, [env_name, env_value])
@impl true
def sync(), do: error(:sync, [])
@ -144,11 +143,16 @@ defmodule FarmbotCeleryScript.SysCalls.Stubs do
def write_pin(pin_num, pin_mode, pin_value),
do: error(:write_pin, [pin_num, pin_mode, pin_value])
@impl true
def update_resource(kind, id, params),
do: error(:update_resource, [kind, id, params])
@impl true
def zero(axis), do: error(:zero, [axis])
@impl true
def eval_assertion(comment, expression), do: error(:eval_assertion, [comment, expression])
def eval_assertion(comment, expression),
do: error(:eval_assertion, [comment, expression])
defp error(fun, _args) do
msg = """

View File

@ -1,7 +1,12 @@
defmodule FarmbotCeleryScript.MixProject do
use Mix.Project
@version Path.join([__DIR__, "..", "VERSION"]) |> File.read!() |> String.trim()
@elixir_version Path.join([__DIR__, "..", "ELIXIR_VERSION"]) |> File.read!() |> String.trim()
@version Path.join([__DIR__, "..", "VERSION"])
|> File.read!()
|> String.trim()
@elixir_version Path.join([__DIR__, "..", "ELIXIR_VERSION"])
|> File.read!()
|> String.trim()
def project do
[
@ -39,7 +44,11 @@ defmodule FarmbotCeleryScript.MixProject do
end
def elixirc_paths(:test),
do: ["lib", Path.expand("./test/support"), Path.expand("../test/support/celery_script")]
do: [
"lib",
Path.expand("./test/support"),
Path.expand("../test/support/celery_script")
]
def elixirc_paths(_), do: ["lib"]
@ -57,7 +66,9 @@ defmodule FarmbotCeleryScript.MixProject do
{:jason, "~> 1.1"},
{:timex, "~> 3.4"},
{:excoveralls, "~> 0.10", only: [:test], targets: [:host]},
{:dialyxir, "~> 1.0.0-rc.3", only: [:dev], targets: [:host], runtime: false},
{:mimic, "~> 1.1", only: :test},
{:dialyxir, "~> 1.0.0-rc.3",
only: [:dev], targets: [:host], runtime: false},
{:ex_doc, "~> 0.21.2", only: [:dev], targets: [:host], runtime: false}
]
end

View File

@ -13,6 +13,7 @@
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"mimic": {:hex, :mimic, "1.1.3", "3bad83d5271b4faa7bbfef587417a6605cbbc802a353395d446a1e5f46fe7115", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},

View File

@ -0,0 +1,4 @@
defmodule FarmbotCeleryScript.DotPropsTest do
use ExUnit.Case
doctest FarmbotCeleryScript.DotProps, import: true
end

View File

@ -0,0 +1,4 @@
defmodule FarmbotCeleryScript.AST.FactoryTest do
use ExUnit.Case, async: true
doctest FarmbotCeleryScript.AST.Factory, import: true
end

View File

@ -0,0 +1,122 @@
defmodule FarmbotCeleryScript.CompilerGroupsTest do
use ExUnit.Case, async: true
use Mimic
alias FarmbotCeleryScript.AST
alias FarmbotCeleryScript.SysCalls.Stubs
alias FarmbotCeleryScript.Compiler.Sequence
setup :verify_on_exit!
test "compilation of point_group in parameter application" do
fake_point_ids = [4, 5, 6, 7]
expect(Stubs, :find_points_via_group, fn _ ->
%{name: "woosh", point_ids: fake_point_ids}
end)
expect(Stubs, :point, 4, fn _kind, id ->
# EDGE CASE: Handle malformed stuff by ensuring that 50% of
# points have no name.
if rem(id, 2) == 0 do
%{name: "from the test suite %%", x: 6, y: 7, z: 8}
else
%{x: 6, y: 7, z: 8}
end
end)
result = Sequence.sequence(fake_ast(), [])
length1 = 2 + length(fake_point_ids)
length2 = length(result)
assert length2 === length1
# ============================================
# ABOUT THIS (brittle) TEST:
# You should not write tests like this and
# there is a high liklihood that the code below
# will break in the future.
# This is especially true if you intend to change
# the behavior of Sequence.sequence/2.
# If you WERE NOT EXPECTING to change the behavior
# of Sequence.sequence/2 and this test fails,
# you should consider it a true failure that
# requires investigation.
# IT IS OK TO REPLACE THIS TEST WITH BETTER
# TESTS.
# ============================================
canary_actual = :crypto.hash(:sha, Macro.to_string(result))
canary_expected =
<<136, 140, 48, 226, 216, 155, 178, 103, 244, 88, 225, 146, 130, 216, 125,
72, 113, 195, 65, 1>>
# READ THE NOTE ABOVE IF THIS TEST FAILS!!!
assert canary_expected == canary_actual
end
defp fake_ast() do
%AST{
args: %{
locals: %AST{
args: %{},
body: [
%AST{
args: %{
default_value: %AST{
args: %{pointer_id: 1670, pointer_type: "Plant"},
body: [],
comment: nil,
kind: :point,
meta: nil
},
label: "parent"
},
body: [],
comment: nil,
kind: :parameter_declaration,
meta: nil
},
%AST{
args: %{
data_value: %AST{
args: %{point_group_id: 34},
body: [],
comment: nil,
kind: :point_group,
meta: nil
},
label: "parent"
},
body: [],
comment: nil,
kind: :parameter_application,
meta: nil
}
],
comment: nil,
kind: :scope_declaration,
meta: nil
},
sequence_name: "Pogo",
version: 20_180_209
},
body: [
%AST{
kind: :move_absolute,
args: %{
speed: 100,
location: %AST{kind: :identifier, args: %{label: "parent"}},
offset: %AST{
kind: :coordinate,
args: %{x: -20, y: -20, z: -20}
}
},
body: []
}
],
comment: nil,
kind: :sequence,
meta: %{sequence_name: "Pogo"}
}
end
end

View File

@ -34,7 +34,10 @@ defmodule FarmbotCeleryScript.CompilerTest do
# The compiler expects the `env` argument to be already sanatized.
# When supplying the env for this test, we need to make sure the
# `provided_by_caller` variable name is sanatized
sanatized_env = [{IdentifierSanitizer.to_variable("provided_by_caller"), 900}]
sanatized_env = [
{IdentifierSanitizer.to_variable("provided_by_caller"), 900}
]
[body_item] = Compiler.compile(sequence, sanatized_env)
assert body_item.() == 900
@ -48,7 +51,9 @@ defmodule FarmbotCeleryScript.CompilerTest do
}
]
compiled_celery_env = Compiler.Utils.compile_params_to_function_args(celery_env, [])
compiled_celery_env =
Compiler.Utils.compile_params_to_function_args(celery_env, [])
[body_item] = Compiler.compile(sequence, compiled_celery_env)
assert body_item.() == 600
end
@ -74,12 +79,15 @@ defmodule FarmbotCeleryScript.CompilerTest do
end
test "identifier sanitization" do
label = "System.cmd(\"rm\", [\"-rf /*\"])"
label = "System.cmd(\"echo\", [\"lol\"])"
value_ast = AST.Factory.new("coordinate", x: 1, y: 1, z: 1)
identifier_ast = AST.Factory.new("identifier", label: label)
parameter_application_ast =
AST.Factory.new("parameter_application", label: label, data_value: value_ast)
AST.Factory.new("parameter_application",
label: label,
data_value: value_ast
)
celery_ast = %AST{
kind: :sequence,
@ -112,11 +120,19 @@ defmodule FarmbotCeleryScript.CompilerTest do
[
fn params ->
_ = inspect(params)
unsafe_U3lzdGVtLmNtZCgiZWNobyIsIFsibG9sIl0p = FarmbotCeleryScript.SysCalls.coordinate(1, 1, 1)
#{var_name} =
FarmbotCeleryScript.SysCalls.coordinate(1, 1, 1)
better_params = %{
"System.cmd(\\"echo\\", [\\"lol\\"])" => %FarmbotCeleryScript.AST{
args: %{x: 1, y: 1, z: 1},
body: [],
comment: nil,
kind: :coordinate,
meta: nil
}
}
[fn -> #{var_name} end]
[fn -> unsafe_U3lzdGVtLmNtZCgiZWNobyIsIFsibG9sIl0p end]
end
]
""")
@ -347,6 +363,114 @@ defmodule FarmbotCeleryScript.CompilerTest do
""")
end
test "`update_resource`: " do
compiled =
"test/fixtures/mark_variable_removed.json"
|> File.read!()
|> Jason.decode!()
|> AST.decode()
|> compile()
assert compiled ==
strip_nl("""
[
fn params ->
_ = inspect(params)
unsafe_cGFyZW50 =
Keyword.get(params, :unsafe_cGFyZW50, FarmbotCeleryScript.SysCalls.coordinate(1, 2, 3))
better_params = %{}
[
fn ->
me = FarmbotCeleryScript.Compiler.UpdateResource
variable = %FarmbotCeleryScript.AST{
args: %{label: "parent"},
body: [],
comment: nil,
kind: :identifier,
meta: nil
}
update = %{"plant_stage" => "removed"}
case(variable) do
%AST{kind: :identifier} ->
args = Map.fetch!(variable, :args)
label = Map.fetch!(args, :label)
resource = Map.fetch!(better_params, label)
me.do_update(resource, update)
%AST{kind: :point} ->
me.do_update(variable.args(), update)
%AST{kind: :resource} ->
me.do_update(variable.args(), update)
res ->
raise("Resource error. Please notfiy support: \#{inspect(res)}")
end
end
]
end
]
""")
end
test "`update_resource`: Multiple fields of `resource` type." do
compiled =
"test/fixtures/update_resource_multi.json"
|> File.read!()
|> Jason.decode!()
|> AST.decode()
|> compile()
assert compiled ==
strip_nl("""
[
fn params ->
_ = inspect(params)
better_params = %{}
[
fn ->
me = FarmbotCeleryScript.Compiler.UpdateResource
variable = %FarmbotCeleryScript.AST{
args: %{resource_id: 23, resource_type: "Plant"},
body: [],
comment: nil,
kind: :resource,
meta: nil
}
update = %{"plant_stage" => "planted", "r" => 23}
case(variable) do
%AST{kind: :identifier} ->
args = Map.fetch!(variable, :args)
label = Map.fetch!(args, :label)
resource = Map.fetch!(better_params, label)
me.do_update(resource, update)
%AST{kind: :point} ->
me.do_update(variable.args(), update)
%AST{kind: :resource} ->
me.do_update(variable.args(), update)
res ->
raise("Resource error. Please notfiy support: \#{inspect(res)}")
end
end
]
end
]
""")
end
defp compile(ast) do
ast
|> Compiler.compile_ast([])

View File

@ -3,7 +3,10 @@ defmodule FarmbotCeleryScript.Corpus.NodeTest do
alias FarmbotCeleryScript.Corpus
test "inspect" do
assert "Sequence(version, locals) [calibrate, change_ownership, check_updates, dump_info, emergency_lock, emergency_unlock, execute, execute_script, factory_reset, find_home, flash_firmware, home, install_farmware, install_first_party_farmware, _if, move_absolute, move_relative, power_off, read_pin, read_status, reboot, remove_farmware, resource_update, send_message, set_servo_angle, set_user_env, sync, take_photo, toggle_pin, update_farmware, wait, write_pin, zero]" =
inspect(Corpus.sequence())
a =
"Sequence(version, locals) [assertion, calibrate, change_ownership, check_updates, emergency_lock, emergency_unlock, execute, execute_script, factory_reset, find_home, flash_firmware, home, install_farmware, install_first_party_farmware, _if, move_absolute, move_relative, power_off, read_pin, read_status, reboot, remove_farmware, update_resource, send_message, set_servo_angle, set_user_env, sync, take_photo, toggle_pin, update_farmware, wait, write_pin, zero]"
b = inspect(Corpus.sequence())
assert a == b
end
end

View File

@ -1,33 +1,35 @@
defmodule FarmbotCeleryScript.SchedulerTest do
use ExUnit.Case
use Mimic
alias FarmbotCeleryScript.{Scheduler, AST}
alias Farmbot.TestSupport.CeleryScript.TestSysCalls
alias FarmbotCeleryScript.SysCalls.Stubs
import ExUnit.CaptureLog
setup do
{:ok, shim} = TestSysCalls.checkout()
{:ok, sch} = Scheduler.start_link([registry_name: :"#{:random.uniform()}"], [])
[shim: shim, sch: sch]
end
setup :set_mimic_global
setup :verify_on_exit!
test "schedules a sequence to run in the future" do
expect(Stubs, :read_pin, 1, fn _num, _mode ->
23
end)
{:ok, sch} =
Scheduler.start_link([registry_name: :"#{:random.uniform()}"], [])
test "schedules a sequence to run in the future", %{sch: sch} do
ast =
AST.Factory.new()
|> AST.Factory.rpc_request("hello world")
|> AST.Factory.read_pin(9, 0)
pid = self()
:ok =
TestSysCalls.handle(TestSysCalls, fn
:read_pin, args ->
send(pid, {:read_pin, args})
1
end)
scheduled_time = DateTime.utc_now() |> DateTime.add(100, :millisecond)
# msg = "[info] Next execution is ready for execution: now"
{:ok, _} = Scheduler.schedule(sch, ast, scheduled_time, %{})
# Hack to force the scheduler to checkup instead of waiting the normal 15 seconds
send(sch, :checkup)
assert_receive {:read_pin, [9, 0]}, 1000
assert capture_log(fn ->
send(sch, :checkup)
# Sorry.
Process.sleep(1100)
end) =~ "[info] Next execution is ready for execution: now"
end
end

View File

@ -1,178 +1,240 @@
defmodule FarmbotCeleryScript.SysCallsTest do
use ExUnit.Case, async: false
alias Farmbot.TestSupport.CeleryScript.TestSysCalls
alias FarmbotCeleryScript.{AST, SysCalls}
use Mimic
setup do
{:ok, shim} = TestSysCalls.checkout()
[shim: shim]
alias FarmbotCeleryScript.{
SysCalls,
SysCalls.Stubs,
AST
}
setup :verify_on_exit!
test "point, OK" do
expect(Stubs, :point, 1, fn _kind, 1 ->
%{x: 100, y: 200, z: 300}
end)
result1 = SysCalls.point(Stubs, "Peripheral", 1)
assert %{x: 100, y: 200, z: 300} == result1
end
test "point", %{shim: shim} do
:ok = shim_fun_ok(shim, %{x: 100, y: 200, z: 300})
assert %{x: 100, y: 200, z: 300} = SysCalls.point(TestSysCalls, "Peripheral", 1)
assert_receive {:point, ["Peripheral", 1]}
test "point, NO" do
expect(Stubs, :point, 1, fn _kind, 0 ->
:whatever
end)
:ok = shim_fun_error(shim, "point error")
assert {:error, "point error"} == SysCalls.point(TestSysCalls, "Peripheral", 1)
boom = fn -> SysCalls.point(Stubs, "Peripheral", 0) end
assert_raise FarmbotCeleryScript.RuntimeError, boom
end
test "move_absolute", %{shim: shim} do
:ok = shim_fun_ok(shim)
assert :ok = SysCalls.move_absolute(TestSysCalls, 1, 2, 3, 4)
assert_receive {:move_absolute, [1, 2, 3, 4]}
test "point groups failure" do
expect(Stubs, :find_points_via_group, 1, fn _id ->
:whatever
end)
:ok = shim_fun_error(shim, "move failed!")
assert {:error, "move failed!"} == SysCalls.move_absolute(TestSysCalls, 1, 2, 3, 4)
boom = fn -> SysCalls.find_points_via_group(Stubs, :something_else) end
assert_raise FarmbotCeleryScript.RuntimeError, boom
end
test "get current positions", %{shim: shim} do
:ok = shim_fun_ok(shim, 100.00)
assert 100.00 = SysCalls.get_current_x(TestSysCalls)
assert 100.00 = SysCalls.get_current_y(TestSysCalls)
assert 100.00 = SysCalls.get_current_z(TestSysCalls)
test "point groups success" do
expect(Stubs, :find_points_via_group, 1, fn _id ->
%{point_ids: [1, 2, 3]}
end)
assert_receive {:get_current_x, []}
assert_receive {:get_current_y, []}
assert_receive {:get_current_z, []}
:ok = shim_fun_error(shim, "firmware error")
assert {:error, "firmware error"} == SysCalls.get_current_x(TestSysCalls)
assert {:error, "firmware error"} == SysCalls.get_current_y(TestSysCalls)
assert {:error, "firmware error"} == SysCalls.get_current_z(TestSysCalls)
pg = %{point_ids: [1, 2, 3]}
result = SysCalls.find_points_via_group(Stubs, 456)
assert result == pg
end
test "write_pin", %{shim: shim} do
:ok = shim_fun_ok(shim)
assert :ok = SysCalls.write_pin(TestSysCalls, 1, 0, 1)
assert :ok = SysCalls.write_pin(TestSysCalls, %{type: "boxled", id: 4}, 0, 1)
assert :ok = SysCalls.write_pin(TestSysCalls, %{type: "boxled", id: 3}, 1, 123)
test "move_absolute, OK" do
expect(Stubs, :move_absolute, 1, fn 1, 2, 3, 4 ->
:ok
end)
assert_receive {:write_pin, [1, 0, 1]}
assert_receive {:write_pin, [%{type: "boxled", id: 4}, 0, 1]}
assert_receive {:write_pin, [%{type: "boxled", id: 3}, 1, 123]}
:ok = shim_fun_error(shim, "firmware error")
assert {:error, "firmware error"} == SysCalls.write_pin(TestSysCalls, 1, 0, 1)
assert :ok = SysCalls.move_absolute(Stubs, 1, 2, 3, 4)
end
test "read_pin", %{shim: shim} do
:ok = shim_fun_ok(shim, 1)
assert 1 == SysCalls.read_pin(TestSysCalls, 10, 0)
assert 1 == SysCalls.read_pin(TestSysCalls, 77, nil)
assert_receive {:read_pin, [10, 0]}
assert_receive {:read_pin, [77, nil]}
test "move_absolute, NO" do
expect(Stubs, :move_absolute, 1, fn 1, 2, 3, 4 ->
{:error, "move failed!"}
end)
:ok = shim_fun_error(shim, "firmware error")
assert {:error, "firmware error"} == SysCalls.read_pin(TestSysCalls, 1, 0)
assert {:error, "move failed!"} ==
SysCalls.move_absolute(Stubs, 1, 2, 3, 4)
end
test "wait", %{shim: shim} do
:ok = shim_fun_ok(shim)
assert :ok = SysCalls.wait(TestSysCalls, 1000)
assert_receive {:wait, [1000]}
test "get positions, OK" do
expect(Stubs, :get_current_x, 1, fn -> 100.00 end)
expect(Stubs, :get_current_y, 1, fn -> 200.00 end)
expect(Stubs, :get_current_z, 1, fn -> 300.00 end)
assert 100.00 = SysCalls.get_current_x(Stubs)
assert 200.00 = SysCalls.get_current_y(Stubs)
assert 300.00 = SysCalls.get_current_z(Stubs)
end
test "named_pin", %{shim: shim} do
test "get positions, KO" do
expect(Stubs, :get_current_x, 1, fn -> {:error, "L"} end)
expect(Stubs, :get_current_y, 1, fn -> {:error, "O"} end)
expect(Stubs, :get_current_z, 1, fn -> {:error, "L"} end)
assert {:error, "L"} == SysCalls.get_current_x(Stubs)
assert {:error, "O"} == SysCalls.get_current_y(Stubs)
assert {:error, "L"} == SysCalls.get_current_z(Stubs)
end
test "write_pin" do
err = {:error, "firmware error?"}
expect(Stubs, :write_pin, 4, fn pin_num, _, _ ->
if pin_num == 66 do
err
else
:ok
end
end)
assert :ok = SysCalls.write_pin(Stubs, 1, 0, 1)
assert :ok = SysCalls.write_pin(Stubs, %{type: "boxled", id: 4}, 0, 1)
assert :ok = SysCalls.write_pin(Stubs, %{type: "boxled", id: 3}, 1, 123)
assert err == SysCalls.write_pin(Stubs, 66, 0, 1)
end
test "read_pin" do
expect(Stubs, :read_pin, 3, fn num, _mode ->
if num == 1 do
{:error, "firmware error"}
else
num * 2
end
end)
assert 20 == SysCalls.read_pin(Stubs, 10, 0)
assert 30 == SysCalls.read_pin(Stubs, 15, nil)
assert {:error, "firmware error"} == SysCalls.read_pin(Stubs, 1, 0)
end
test "wait" do
expect(Stubs, :wait, fn ms ->
if ms == 1000 do
:ok
end
end)
assert :ok = SysCalls.wait(Stubs, 1000)
end
test "named_pin" do
err = {:error, "error finding resource"}
expect(Stubs, :named_pin, 5, fn kind, num ->
hmm = {kind, num}
case hmm do
{"Peripheral", 5} -> 44
{"Sensor", 1999} -> 55
{"BoxLed", 3} -> %{type: "BoxLed", id: 3}
{"BoxLed", 4} -> %{type: "BoxLed", id: 4}
{"Peripheral", 888} -> err
end
end)
# Peripheral and Sensor are on the Arduino
:ok = shim_fun_ok(shim, 44)
assert 44 == SysCalls.named_pin(TestSysCalls, "Peripheral", 5)
assert 44 == SysCalls.named_pin(TestSysCalls, "Sensor", 1999)
assert 44 == SysCalls.named_pin(Stubs, "Peripheral", 5)
assert 55 == SysCalls.named_pin(Stubs, "Sensor", 1999)
# BoxLed is on the GPIO
:ok = shim_fun_ok(shim, %{type: "BoxLed", id: 3})
assert %{type: "BoxLed", id: 3} == SysCalls.named_pin(TestSysCalls, "BoxLed", 3)
:ok = shim_fun_ok(shim, %{type: "BoxLed", id: 4})
assert %{type: "BoxLed", id: 4} == SysCalls.named_pin(TestSysCalls, "BoxLed", 4)
assert %{type: "BoxLed", id: 3} ==
SysCalls.named_pin(Stubs, "BoxLed", 3)
assert_receive {:named_pin, ["Peripheral", 5]}
assert_receive {:named_pin, ["Sensor", 1999]}
assert_receive {:named_pin, ["BoxLed", 3]}
assert_receive {:named_pin, ["BoxLed", 4]}
assert %{type: "BoxLed", id: 4} ==
SysCalls.named_pin(Stubs, "BoxLed", 4)
:ok = shim_fun_error(shim, "error finding resource")
assert {:error, "error finding resource"} ==
SysCalls.named_pin(TestSysCalls, "Peripheral", 888)
assert err == SysCalls.named_pin(Stubs, "Peripheral", 888)
end
test "send_message", %{shim: shim} do
:ok = shim_fun_ok(shim)
assert :ok = SysCalls.send_message(TestSysCalls, "success", "hello world", ["email"])
assert_receive {:send_message, ["success", "hello world", ["email"]]}
test "send_message" do
err = {:error, "email machine broke"}
:ok = shim_fun_error(shim, "email machine broke")
expect(Stubs, :send_message, 2, fn type, _msg, _chans ->
if type == "error" do
err
else
:ok
end
end)
assert {:error, "email machine broke"} ==
SysCalls.send_message(TestSysCalls, "error", "goodbye world", ["email"])
assert :ok =
SysCalls.send_message(Stubs, "success", "hello world", ["email"])
assert err ==
SysCalls.send_message(Stubs, "error", "goodbye world", ["email"])
end
test "find_home", %{shim: shim} do
:ok = shim_fun_ok(shim)
assert :ok = SysCalls.find_home(TestSysCalls, "x")
assert_receive {:find_home, ["x"]}
test "find_home" do
err = {:error, "home lost"}
:ok = shim_fun_error(shim, "home lost")
expect(Stubs, :find_home, 2, fn axis ->
if axis == "x" do
:ok
else
err
end
end)
assert {:error, "home lost"} == SysCalls.find_home(TestSysCalls, "x")
assert :ok = SysCalls.find_home(Stubs, "x")
assert err == SysCalls.find_home(Stubs, "z")
end
test "execute_script", %{shim: shim} do
:ok = shim_fun_ok(shim)
assert :ok = SysCalls.execute_script(TestSysCalls, "take-photo", %{})
assert_receive {:execute_script, ["take-photo", %{}]}
test "execute_script" do
err = {:error, "not installed"}
:ok = shim_fun_error(shim, "not installed")
expect(Stubs, :execute_script, 2, fn "take-photo", env ->
if Map.get(env, :error) do
err
else
:ok
end
end)
assert {:error, "not installed"} == SysCalls.execute_script(TestSysCalls, "take-photo", %{})
assert :ok = SysCalls.execute_script(Stubs, "take-photo", %{})
assert err == SysCalls.execute_script(Stubs, "take-photo", %{error: true})
end
test "set_servo_angle errors", %{shim: shim} do
:ok = shim_fun_ok(shim)
arg0 = [5, 40]
assert :ok = SysCalls.set_servo_angle(TestSysCalls, "set_servo_angle", arg0)
assert_receive {:set_servo_angle, arg0}
test "set_servo_angle errors" do
error = {:error, "boom"}
arg1 = [40, -5]
:ok = shim_fun_error(shim, "boom")
assert {:error, "boom"} == SysCalls.set_servo_angle(TestSysCalls, "set_servo_angle", arg1)
expect(Stubs, :set_servo_angle, 2, fn num, _val ->
if num == 5 do
:ok
else
error
end
end)
assert error == SysCalls.set_servo_angle(Stubs, 40, -5)
assert :ok == SysCalls.set_servo_angle(Stubs, 5, 40)
end
test "get_sequence", %{shim: shim} do
:ok =
shim_fun_ok(shim, %AST{
kind: :sequence,
args: %{locals: %AST{kind: :scope_declaration, args: %{}}}
})
test "get_sequence" do
nothing = %AST{
kind: "nothing",
args: {},
body: []
}
assert %{} = SysCalls.get_sequence(TestSysCalls, 123)
assert_receive {:get_sequence, [123]}
err = {:error, "sequence not found"}
:ok = shim_fun_error(shim, "sequence not found")
expect(Stubs, :get_sequence, 2, fn sequence_id ->
if sequence_id == 321 do
err
else
nothing
end
end)
assert {:error, "sequence not found"} == SysCalls.get_sequence(TestSysCalls, 123)
end
def shim_fun_ok(shim, val \\ :ok) do
pid = self()
:ok =
TestSysCalls.handle(shim, fn kind, args ->
send(pid, {kind, args})
val
end)
end
def shim_fun_error(shim, val) when is_binary(val) do
:ok =
TestSysCalls.handle(shim, fn _kind, _args ->
{:error, val}
end)
assert nothing == SysCalls.get_sequence(Stubs, 123)
assert err == SysCalls.get_sequence(Stubs, 321)
end
end

View File

@ -1,12 +1,14 @@
defmodule FarmbotCeleryScriptTest do
use ExUnit.Case, async: true
alias FarmbotCeleryScript.AST
alias Farmbot.TestSupport.CeleryScript.TestSysCalls
use Mimic
setup do
{:ok, _shim} = TestSysCalls.checkout()
:ok
end
alias FarmbotCeleryScript.AST
alias FarmbotCeleryScript.SysCalls.Stubs
import ExUnit.CaptureIO
import ExUnit.CaptureLog
setup :verify_on_exit!
test "uses default values when no parameter is found" do
sequence_ast =
@ -24,7 +26,7 @@ defmodule FarmbotCeleryScriptTest do
label: "foo",
default_value: %{
kind: :coordinate,
args: %{x: 129, y: 129, z: 129}
args: %{x: 12, y: 11, z: 10}
}
}
}
@ -52,19 +54,18 @@ defmodule FarmbotCeleryScriptTest do
me = self()
:ok =
TestSysCalls.handle(TestSysCalls, fn
:move_absolute, args ->
send(me, {:move_absolute, args})
:ok
expect(Stubs, :coordinate, 2, fn x, y, z ->
%{x: x, y: y, z: z}
end)
:coordinate, [x, y, z] ->
%{x: x, y: y, z: z}
end)
expect(Stubs, :move_absolute, 1, fn _x, _y, _z, _s ->
:ok
end)
_ = FarmbotCeleryScript.execute(sequence_ast, me)
assert_receive {:step_complete, ^me, :ok}
assert_receive {:move_absolute, [129, 129, 129, 921]}
capture_log(fn ->
result = FarmbotCeleryScript.execute(sequence_ast, me)
assert :ok == result
end) =~ "[error] CeleryScript syscall stubbed: log"
end
test "syscall errors" do
@ -78,13 +79,12 @@ defmodule FarmbotCeleryScriptTest do
}
|> AST.decode()
:ok =
TestSysCalls.handle(TestSysCalls, fn
:read_pin, _ -> {:error, "failed to read pin!"}
end)
expect(Stubs, :read_pin, 1, fn _, _ -> {:error, "failed to read pin!"} end)
result = FarmbotCeleryScript.execute(execute_ast, execute_ast)
assert {:error, "failed to read pin!"} = result
assert {:error, "failed to read pin!"} = FarmbotCeleryScript.execute(execute_ast, execute_ast)
assert_receive {:step_complete, ^execute_ast, {:error, "failed to read pin!"}}
assert_receive {:step_complete, ^execute_ast,
{:error, "failed to read pin!"}}
end
test "regular exceptions still occur" do
@ -98,12 +98,17 @@ defmodule FarmbotCeleryScriptTest do
}
|> AST.decode()
:ok =
TestSysCalls.handle(TestSysCalls, fn
:read_pin, _ -> raise("big oops")
expect(Stubs, :read_pin, fn _, _ ->
raise("big oops")
end)
io =
capture_io(:stderr, fn ->
assert {:error, "big oops"} ==
FarmbotCeleryScript.execute(execute_ast, execute_ast)
end)
assert {:error, "big oops"} == FarmbotCeleryScript.execute(execute_ast, execute_ast)
assert io =~ "CeleryScript Exception"
assert_receive {:step_complete, ^execute_ast, {:error, "big oops"}}
end
end

View File

@ -0,0 +1,48 @@
{
"args": {
"locals": {
"args": {},
"body": [
{
"args": {
"default_value": {
"args": {
"x": 1,
"y": 2,
"z": 3
},
"kind": "coordinate"
},
"label": "parent"
},
"kind": "parameter_declaration"
}
],
"kind": "scope_declaration"
},
"version": -999
},
"body": [
{
"args": {
"resource": {
"args": {
"label": "parent"
},
"kind": "identifier"
}
},
"body": [
{
"args": {
"label": "meta.my_prop",
"value": "whatever"
},
"kind": "pair"
}
],
"kind": "update_resource"
}
],
"kind": "sequence"
}

View File

@ -0,0 +1,48 @@
{
"args": {
"locals": {
"args": {},
"body": [
{
"args": {
"default_value": {
"args": {
"x": 1,
"y": 2,
"z": 3
},
"kind": "coordinate"
},
"label": "parent"
},
"kind": "parameter_declaration"
}
],
"kind": "scope_declaration"
},
"version": -999
},
"body": [
{
"args": {
"resource": {
"args": {
"label": "parent"
},
"kind": "identifier"
}
},
"body": [
{
"args": {
"label": "plant_stage",
"value": "removed"
},
"kind": "pair"
}
],
"kind": "update_resource"
}
],
"kind": "sequence"
}

View File

@ -0,0 +1,34 @@
{
"args": {
"locals": {
"args": {},
"body": [],
"kind": "scope_declaration"
},
"version": -999
},
"body": [
{
"args": {
"resource": {
"args": {
"resource_id": 0,
"resource_type": "Device"
},
"kind": "resource"
}
},
"body": [
{
"args": {
"label": "mounted_tool_id",
"value": 12161
},
"kind": "pair"
}
],
"kind": "update_resource"
}
],
"kind": "sequence"
}

View File

@ -0,0 +1,41 @@
{
"args": {
"locals": {
"args": {},
"body": [],
"kind": "scope_declaration"
},
"version": -999
},
"body": [
{
"args": {
"resource": {
"args": {
"resource_id": 23,
"resource_type": "Plant"
},
"kind": "resource"
}
},
"body": [
{
"args": {
"label": "plant_stage",
"value": "planted"
},
"kind": "pair"
},
{
"args": {
"label": "r",
"value": 23
},
"kind": "pair"
}
],
"kind": "update_resource"
}
],
"kind": "sequence"
}

View File

@ -1 +1,3 @@
Application.ensure_all_started(:mimic)
Mimic.copy(FarmbotCeleryScript.SysCalls.Stubs)
ExUnit.start()

View File

@ -1,5 +1,6 @@
[
import_deps: [:ecto],
line_length: 80,
inputs: [
"*.{ex,exs}",
"{config,priv,test}/**/*.{ex,exs}",

View File

@ -1,51 +1,52 @@
use Mix.Config
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmEvent, checkup_time_ms: 10_000
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmEvent,
checkup_time_ms: 10_000
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.RegimenInstance,
checkup_time_ms: 10_000
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmwareInstallation,
error_retry_time_ms: 30_000,
install_dir: "/tmp/farmware"
config :farmbot_core,
FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmwareInstallation,
error_retry_time_ms: 30_000,
install_dir: "/tmp/farmware"
config :farmbot_core, FarmbotCore.FarmwareRuntime, runtime_dir: "/tmp/farmware_runtime"
config :farmbot_core, FarmbotCore.FarmwareRuntime,
runtime_dir: "/tmp/farmware_runtime"
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.PinBinding,
gpio_handler: FarmbotCore.PinBindingWorker.StubGPIOHandler,
error_retry_time_ms: 30_000
config :farmbot_core, Elixir.FarmbotCore.AssetWorker.FarmbotCore.Asset.PublicKey,
ssh_handler: FarmbotCore.PublicKeyHandler.StubSSHHandler
config :farmbot_core,
Elixir.FarmbotCore.AssetWorker.FarmbotCore.Asset.PublicKey,
ssh_handler: FarmbotCore.PublicKeyHandler.StubSSHHandler
config :farmbot_core, FarmbotCore.AssetMonitor, checkup_time_ms: 30_000
config :farmbot_core, FarmbotCore.Leds, gpio_handler: FarmbotCore.Leds.StubHandler
config :farmbot_core, FarmbotCore.Leds,
gpio_handler: FarmbotCore.Leds.StubHandler
config :farmbot_core, FarmbotCore.JSON, json_parser: FarmbotCore.JSON.JasonParser
config :farmbot_core, FarmbotCore.JSON,
json_parser: FarmbotCore.JSON.JasonParser
config :farmbot_core, FarmbotCore.BotState.FileSystem,
root_dir: "/tmp/farmbot",
sleep_time: 200
config :farmbot_core, FarmbotCore.EctoMigrator,
expected_fw_versions: ["6.4.2.F", "6.4.2.R", "6.4.2.G"],
default_firmware_io_logs: false,
default_server: "https://my.farm.bot",
default_dns_name: "my.farm.bot",
default_ntp_server_1: "0.pool.ntp.org",
default_ntp_server_2: "1.pool.ntp.org",
default_currently_on_beta:
String.contains?(to_string(:os.cmd('git rev-parse --abbrev-ref HEAD')), "beta")
String.contains?(
to_string(:os.cmd('git rev-parse --abbrev-ref HEAD')),
"beta"
)
config :farmbot_core, FarmbotCore.FirmwareTTYDetector, expected_names: []
config :farmbot_core, FarmbotCore.FirmwareOpenTask, attempt_threshold: 5
config :farmbot_firmware, FarmbotFirmware, reset: FarmbotFirmware.NullReset
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FbosConfig,
firmware_flash_attempt_threshold: 5
config :farmbot_firmware, FarmbotFirmware, reset: FarmbotCore.FirmwareResetter
import_config "ecto.exs"
import_config "logger.exs"

View File

@ -2,8 +2,3 @@ use Mix.Config
config :farmbot_celery_script, FarmbotCeleryScript.SysCalls,
sys_calls: FarmbotCeleryScript.SysCalls.Stubs
config :farmbot_core, FarmbotCore.FirmwareOpenTask, attempt_threshold: 5
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FbosConfig,
firmware_flash_attempt_threshold: 5

View File

@ -2,7 +2,11 @@ use Mix.Config
config :ecto, json_library: FarmbotCore.JSON
config :farmbot_core,
ecto_repos: [FarmbotCore.Config.Repo, FarmbotCore.Logger.Repo, FarmbotCore.Asset.Repo]
ecto_repos: [
FarmbotCore.Config.Repo,
FarmbotCore.Logger.Repo,
FarmbotCore.Asset.Repo
]
config :farmbot_core, FarmbotCore.Config.Repo,
adapter: Sqlite.Ecto2,

View File

@ -1,18 +1,36 @@
use Mix.Config
config :logger, level: :warn
# must be lower than other timers
# To ensure other timers have time to timeout
config :farmbot_core, FarmbotCore.AssetMonitor, checkup_time_ms: 500
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmEvent, checkup_time_ms: 1000
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmEvent,
checkup_time_ms: 1000
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.RegimenInstance,
checkup_time_ms: 1000
config :farmbot_celery_script, FarmbotCeleryScript.SysCalls,
sys_calls: Farmbot.TestSupport.CeleryScript.TestSysCalls
sys_calls: FarmbotCeleryScript.SysCalls.Stubs
config :farmbot_core, FarmbotCore.FirmwareOpenTask, attempt_threshold: 0
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FbosConfig,
firmware_flash_attempt_threshold: 0
if Mix.env() == :test do
config :ex_unit, capture_logs: true
mapper = fn mod -> config :farmbot_core, mod, children: [] end
list = [
FarmbotCore,
FarmbotCore.StorageSupervisor,
FarmbotCore.Asset.Supervisor,
FarmbotCore.BotState.Supervisor,
FarmbotCore.Config.Supervisor,
FarmbotCore.Logger.Supervisor
]
Enum.map(list, mapper)
end

View File

@ -0,0 +1,6 @@
{
"coverage_options": {
"treat_no_relevant_lines_as_covered": true,
"minimum_coverage": 25
}
}

View File

@ -14,8 +14,11 @@ defmodule FarmbotCore do
def start(_, args), do: Supervisor.start_link(__MODULE__, args, name: __MODULE__)
def init([]) do
Supervisor.init(children(), [strategy: :one_for_one])
end
children = [
def children do
default = [
FarmbotCore.Leds,
FarmbotCore.EctoMigrator,
FarmbotCore.BotState.Supervisor,
@ -24,9 +27,13 @@ defmodule FarmbotCore do
FarmbotCore.FirmwareOpenTask,
FarmbotCore.FirmwareEstopTimer,
# Also error handling for a transport not starting ?
{FarmbotFirmware, transport: FarmbotFirmware.StubTransport, side_effects: FarmbotCore.FirmwareSideEffects},
{FarmbotFirmware,
transport: FarmbotFirmware.StubTransport,
side_effects: FarmbotCore.FirmwareSideEffects,
reset: FarmbotCore.FirmwareResetter},
FarmbotCeleryScript.Scheduler
]
Supervisor.init(children, [strategy: :one_for_one])
config = (Application.get_env(:farmbot_ext, __MODULE__) || [])
Keyword.get(config, :children, default)
end
end

View File

@ -6,16 +6,15 @@ defmodule FarmbotCore.Asset do
"""
alias FarmbotCore.Asset.{
Repo,
CriteriaRetriever,
Device,
DeviceCert,
DiagnosticDump,
FarmwareEnv,
FirstPartyFarmware,
FarmwareInstallation,
FarmEvent,
FarmwareEnv,
FarmwareInstallation,
FbosConfig,
FirmwareConfig,
FirstPartyFarmware,
Peripheral,
PinBinding,
Point,
@ -23,10 +22,11 @@ defmodule FarmbotCore.Asset do
PublicKey,
Regimen,
RegimenInstance,
Sequence,
Repo,
Sensor,
SensorReading,
Tool
Sequence,
Tool,
}
alias FarmbotCore.AssetSupervisor
@ -54,6 +54,7 @@ defmodule FarmbotCore.Asset do
if device = Repo.get_by(Device, id: id) do
Repo.delete!(device)
end
:ok
end
@ -61,11 +62,6 @@ defmodule FarmbotCore.Asset do
## Begin FarmEvent
@doc "Returns all FarmEvents"
def list_farm_events do
Repo.all(FarmEvent)
end
def new_farm_event!(params) do
%FarmEvent{}
|> FarmEvent.changeset(params)
@ -78,13 +74,14 @@ defmodule FarmbotCore.Asset do
end
def update_farm_event!(farm_event, params) do
farm_event =
farm_event |>
FarmEvent.changeset(params)
farm_event =
farm_event
|> FarmEvent.changeset(params)
|> Repo.update!()
if farm_event.executable_type == "Regimen" do
regimen_instance = get_regimen_instance(farm_event)
if regimen_instance do
regimen_instance
|> Repo.preload([:farm_event, :regimen])
@ -111,9 +108,11 @@ defmodule FarmbotCore.Asset do
def get_farm_event_execution(%FarmEvent{} = farm_event, scheduled_at) do
Repo.one(
from e in FarmEvent.Execution,
where: e.farm_event_local_id == ^farm_event.local_id
and e.scheduled_at == ^scheduled_at
from(e in FarmEvent.Execution,
where:
e.farm_event_local_id == ^farm_event.local_id and
e.scheduled_at == ^scheduled_at
)
)
end
@ -149,6 +148,7 @@ defmodule FarmbotCore.Asset do
if fbos_config = Repo.get_by(FbosConfig, id: id) do
Repo.delete!(fbos_config)
end
:ok
end
@ -177,6 +177,7 @@ defmodule FarmbotCore.Asset do
if firmware_config = Repo.get_by(FirmwareConfig, id: id) do
Repo.delete!(firmware_config)
end
:ok
end
@ -192,12 +193,19 @@ defmodule FarmbotCore.Asset do
end
def get_regimen_instance(%FarmEvent{} = farm_event) do
regimen = Repo.one(from r in Regimen, where: r.id == ^farm_event.executable_id)
regimen && Repo.one(from ri in RegimenInstance, where: ri.regimen_id == ^regimen.local_id and ri.farm_event_id == ^farm_event.local_id)
regimen = Repo.one(from(r in Regimen, where: r.id == ^farm_event.executable_id))
regimen &&
Repo.one(
from(ri in RegimenInstance,
where: ri.regimen_id == ^regimen.local_id and ri.farm_event_id == ^farm_event.local_id
)
)
end
def new_regimen_instance!(%FarmEvent{} = farm_event, params \\ %{}) do
regimen = Repo.one!(from r in Regimen, where: r.id == ^farm_event.executable_id)
regimen = Repo.one!(from(r in Regimen, where: r.id == ^farm_event.executable_id))
RegimenInstance.changeset(%RegimenInstance{}, params)
|> Ecto.Changeset.put_assoc(:regimen, regimen)
|> Ecto.Changeset.put_assoc(:farm_event, farm_event)
@ -207,7 +215,7 @@ defmodule FarmbotCore.Asset do
def delete_regimen_instance!(%RegimenInstance{} = ri) do
Repo.delete!(ri)
end
def add_execution_to_regimen_instance!(%RegimenInstance{} = ri, params \\ %{}) do
%RegimenInstance.Execution{}
|> RegimenInstance.Execution.changeset(params)
@ -217,9 +225,11 @@ defmodule FarmbotCore.Asset do
def get_regimen_instance_execution(%RegimenInstance{} = ri, scheduled_at) do
Repo.one(
from e in RegimenInstance.Execution,
where: e.regimen_instance_local_id == ^ri.local_id
and e.scheduled_at == ^scheduled_at
from(e in RegimenInstance.Execution,
where:
e.regimen_instance_local_id == ^ri.local_id and
e.scheduled_at == ^scheduled_at
)
)
end
@ -241,14 +251,30 @@ defmodule FarmbotCore.Asset do
end
def update_point(point, params) do
point
|> Point.changeset(params)
# TODO: RC 8 MAY 2020 - We need to hard refresh the point.
# The CSVM appears to be caching resources. This leads
# to problems when a user runs a sequence that has two
# MARK AS steps.
# NOTE: Updating the `meta` attribute is a _replace_ action
# by default, not a merge action.
# MORE NOTES: Mixed keys (symbol vs. string) will crash this FN.
# Let's just stringify everything...
new_meta = params[:meta] || params["meta"] || %{}
old_meta = point.meta || %{}
updated_meta = Map.merge(old_meta, new_meta)
clean_params = params
|> Map.merge(%{meta: updated_meta})
|> Enum.map(fn {k, v} -> {"#{k}", v} end)
|> Map.new()
Repo.get_by(Point, id: point.id)
|> Point.changeset(clean_params)
|> Repo.update()
end
@doc "Returns all points matching Point.pointer_type"
def get_all_points_by_type(type, order_by \\ "random") do
(from p in Point, where: p.pointer_type == ^type and is_nil(p.discarded_at))
from(p in Point, where: p.pointer_type == ^type and is_nil(p.discarded_at))
|> Repo.all()
|> sort_points(order_by)
end
@ -257,7 +283,7 @@ defmodule FarmbotCore.Asset do
points
|> Enum.group_by(&group_points_by(&1, order_by))
|> Enum.sort(&group_sort(&1, &2, order_by))
|> Enum.map(fn({_group_index, group}) -> Enum.sort(group, &sort_points(&1, &2, order_by)) end)
|> Enum.map(fn {_group_index, group} -> Enum.sort(group, &sort_points(&1, &2, order_by)) end)
|> List.flatten()
end
@ -272,7 +298,6 @@ defmodule FarmbotCore.Asset do
def group_sort({lgroup, _}, {rgroup, _}, "yx_descending"), do: lgroup >= rgroup
def group_sort(_, _, "random"), do: Enum.random([true, false])
def sort_points(%{y: ly}, %{y: ry}, "xy_ascending"), do: ly <= ry
def sort_points(%{y: ly}, %{y: ry}, "xy_descending"), do: ly >= ry
def sort_points(%{x: lx}, %{x: rx}, "yx_ascending"), do: lx <= rx
@ -285,15 +310,15 @@ defmodule FarmbotCore.Asset do
def get_point_group(params) do
case Repo.get_by(PointGroup, params) do
nil ->
nil ->
nil
%{sort_type: nil} = group ->
group
%{sort_type: nil} = group ->
group
%{point_ids: unsorted, sort_type: sort_by} = point_group ->
sorted =
Repo.all(from p in Point, where: p.id in ^unsorted)
sorted =
Repo.all(from(p in Point, where: p.id in ^unsorted))
|> sort_points(sort_by)
|> Enum.map(&Map.fetch!(&1, :id))
@ -301,6 +326,30 @@ defmodule FarmbotCore.Asset do
end
end
def find_points_via_group(id) do
case Repo.get_by(PointGroup, id: id) do
%{id: _id, sort_type: sort_by} = point_group ->
# I don't like this because it makes the code
# harder to understand.
# We are essentially patching the value of
# point_group.point_ids with additional IDs.
# Keep this in mind when debugging sequences
# that deal with point groups- the point_ids
# value is not a reflection of what is in
# the DB / API.
sorted = CriteriaRetriever.run(point_group)
|> sort_points(sort_by || "xy_ascending")
|> Enum.map(fn point -> point.id end)
%{ point_group | point_ids: sorted }
other ->
# Swallow all other errors
a = inspect(id)
b = inspect(other)
Logger.debug("Unexpected point group #{a} #{b}")
nil
end
end
def new_point_group!(params) do
%PointGroup{}
|> PointGroup.changeset(params)
@ -308,13 +357,13 @@ defmodule FarmbotCore.Asset do
end
def update_point_group!(point_group, params) do
updated =
updated =
point_group
|> PointGroup.changeset(params)
|> Repo.update!()
regimen_instances = list_regimen_instances()
farm_events = list_farm_events()
farm_events = Repo.all(FarmEvent)
# check for any matching asset using this point group.
# This is pretty recursive and probably isn't super great
@ -322,11 +371,11 @@ defmodule FarmbotCore.Asset do
for asset <- farm_events ++ regimen_instances do
# TODO(Connor) this might be worth creating a behaviour for
if uses_point_group?(asset, point_group) do
Logger.debug "#{inspect(asset)} uses PointGroup: #{inspect(point_group)}. Reindexing it."
Logger.debug("#{inspect(asset)} uses PointGroup: #{inspect(point_group)}. Reindexing it.")
FarmbotCore.AssetSupervisor.update_child(asset)
end
end
updated
end
@ -335,14 +384,16 @@ defmodule FarmbotCore.Asset do
end
def uses_point_group?(%FarmEvent{body: body}, %PointGroup{id: point_group_id}) do
any_body_node_uses_point_group?(body, point_group_id)
end
def uses_point_group?(%Regimen{body: body, regimen_items: regimen_items}, %PointGroup{id: point_group_id}) do
any_body_node_uses_point_group?(body, point_group_id) || Enum.find(regimen_items, fn(%{sequence_id: sequence_id}) ->
any_body_node_uses_point_group?(get_sequence(sequence_id).body, point_group_id)
end)
def uses_point_group?(%Regimen{body: body, regimen_items: regimen_items}, %PointGroup{
id: point_group_id
}) do
any_body_node_uses_point_group?(body, point_group_id) ||
Enum.find(regimen_items, fn %{sequence_id: sequence_id} ->
any_body_node_uses_point_group?(get_sequence(sequence_id).body, point_group_id)
end)
end
def uses_point_group?(%RegimenInstance{farm_event: farm_event, regimen: regimen}, point_group) do
@ -350,11 +401,13 @@ defmodule FarmbotCore.Asset do
end
def any_body_node_uses_point_group?(body, point_group_id) do
Enum.find(body, fn
Enum.find(body, fn
%{
kind: "execute",
body: execute_body
} -> any_body_node_uses_point_group?(execute_body, point_group_id)
} ->
any_body_node_uses_point_group?(execute_body, point_group_id)
%{
args: %{
"data_value" => %{
@ -364,7 +417,8 @@ defmodule FarmbotCore.Asset do
"label" => "parent"
},
kind: "parameter_application"
} -> true
} ->
true
%{
args: %{
@ -375,8 +429,11 @@ defmodule FarmbotCore.Asset do
"label" => "parent"
},
kind: "parameter_application"
} -> true
_ -> false
} ->
true
_ ->
false
end)
end
@ -407,6 +464,7 @@ defmodule FarmbotCore.Asset do
def new_public_key_from_home!() do
public_key_path = Path.join([System.get_env("HOME"), ".ssh", "id_rsa.pub"])
public_key = File.read!(public_key_path)
%PublicKey{}
|> PublicKey.changeset(%{public_key: public_key})
|> Repo.insert()
@ -417,7 +475,7 @@ defmodule FarmbotCore.Asset do
|> PublicKey.changeset(%{public_key: public_key})
|> Repo.insert()
end
## End PublicKey
## Begin Regimen
@ -435,18 +493,23 @@ defmodule FarmbotCore.Asset do
end
def delete_regimen!(regimen) do
regimen_instances = Repo.all(from ri in RegimenInstance, where: ri.regimen_id == ^regimen.local_id)
regimen_instances =
Repo.all(from(ri in RegimenInstance, where: ri.regimen_id == ^regimen.local_id))
for ri <- regimen_instances do
IO.puts "deleting regimen instance: #{inspect(ri)}"
IO.puts("deleting regimen instance: #{inspect(ri)}")
delete_regimen_instance!(ri)
end
Repo.delete!(regimen)
end
@doc "Update an existing regimen"
def update_regimen!(regimen, params) do
regimen_instances = Repo.all(from ri in RegimenInstance, where: ri.regimen_id == ^regimen.local_id)
|> Repo.preload([:farm_event, :regimen])
regimen_instances =
Repo.all(from(ri in RegimenInstance, where: ri.regimen_id == ^regimen.local_id))
|> Repo.preload([:farm_event, :regimen])
for ri <- regimen_instances do
ri
|> RegimenInstance.changeset(%{updated_at: DateTime.utc_now()})
@ -469,23 +532,31 @@ defmodule FarmbotCore.Asset do
def update_sequence!(%Sequence{} = sequence, params \\ %{}) do
sequence_id = sequence.id
farm_events = Repo.all(from f in FarmEvent,
where: f.executable_type == "Sequence"
and f.executable_id == ^sequence_id)
regimen_instances = RegimenInstance
|> Repo.all()
|> Repo.preload([:regimen, :farm_event])
|> Enum.filter(fn
%{regimen: %{regimen_items: items}} ->
Enum.find(items, fn
%{sequence_id: ^sequence_id} -> true
%{sequence_id: _} -> true
farm_events =
Repo.all(
from(f in FarmEvent,
where:
f.executable_type == "Sequence" and
f.executable_id == ^sequence_id
)
)
regimen_instances =
RegimenInstance
|> Repo.all()
|> Repo.preload([:regimen, :farm_event])
|> Enum.filter(fn
%{regimen: %{regimen_items: items}} ->
Enum.find(items, fn
%{sequence_id: ^sequence_id} -> true
%{sequence_id: _} -> true
end)
%{regimen: nil} ->
false
end)
%{regimen: nil} -> false
end)
for asset <- farm_events ++ regimen_instances do
FarmbotCore.AssetSupervisor.update_child(asset)
end
@ -507,10 +578,11 @@ defmodule FarmbotCore.Asset do
def get_farmware_manifest(package) do
first_party_farmwares = Repo.all(from(fwi in FirstPartyFarmware, select: fwi.manifest))
regular_farmwares = Repo.all(from(fwi in FarmwareInstallation, select: fwi.manifest))
Enum.find(
first_party_farmwares ++ regular_farmwares,
fn
%{package: pkg} -> pkg == package
first_party_farmwares ++ regular_farmwares,
fn
%{package: pkg} -> pkg == package
_ -> false
end
)
@ -519,10 +591,11 @@ defmodule FarmbotCore.Asset do
def get_farmware_installation(package) do
first_party_farmwares = Repo.all(from(fwi in FirstPartyFarmware))
regular_farmwares = Repo.all(from(fwi in FarmwareInstallation))
Enum.find(
first_party_farmwares ++ regular_farmwares,
fn
%{manifest: %{package: pkg}} -> pkg == package
first_party_farmwares ++ regular_farmwares,
fn
%{manifest: %{package: pkg}} -> pkg == package
_ -> false
end
)
@ -530,12 +603,14 @@ defmodule FarmbotCore.Asset do
def upsert_farmware_manifest_by_id(id, params) do
fwi = Repo.get_by(FarmwareInstallation, id: id) || %FarmwareInstallation{}
FarmwareInstallation.changeset(fwi, params)
|> Repo.insert_or_update()
end
def upsert_first_party_farmware_manifest_by_id(id, params) do
fwi = Repo.get_by(FirstPartyFarmware, id: id) || %FirstPartyFarmware{}
FirstPartyFarmware.changeset(fwi, params)
|> Repo.insert_or_update()
end
@ -557,12 +632,14 @@ defmodule FarmbotCore.Asset do
def new_farmware_env(params) do
key = params["key"] || params[:key]
fwe = with key when is_binary(key) <- key,
[fwe | _] <- Repo.all(from fwe in FarmwareEnv, where: fwe.key == ^key) do
fwe
else
_ -> %FarmwareEnv{}
end
fwe =
with key when is_binary(key) <- key,
[fwe | _] <- Repo.all(from(fwe in FarmwareEnv, where: fwe.key == ^key)) do
fwe
else
_ -> %FarmwareEnv{}
end
FarmwareEnv.changeset(fwe, params)
|> Repo.insert_or_update()
@ -596,7 +673,7 @@ defmodule FarmbotCore.Asset do
Sensor.changeset(%Sensor{}, params)
|> Repo.insert!()
end
def update_sensor!(sensor, params) do
sensor
|> Sensor.changeset(params)
@ -624,15 +701,6 @@ defmodule FarmbotCore.Asset do
## End SensorReading
## Begin DiagnosticDump
def new_diagnostic_dump(params) do
DiagnosticDump.changeset(%DiagnosticDump{}, params)
|> Repo.insert()
end
## End DiagnosticDump
## Begin DeviceCert
def new_device_cert(params) do

View File

@ -4,6 +4,7 @@ defmodule FarmbotCore.Asset.Command do
"""
require Logger
alias FarmbotCore.{Asset, Asset.Repo}
alias FarmbotCore.Asset.{
Device,
FarmEvent,
@ -44,31 +45,31 @@ defmodule FarmbotCore.Asset.Command do
:ok
end
def update(Device, _id, params) do
def update(Device, _id, params) do
Asset.update_device!(params)
:ok
end
def update(FbosConfig, id, nil) do
def update(FbosConfig, id, nil) do
Asset.delete_fbos_config!(id)
:ok
end
def update(FbosConfig, _id, params) do
def update(FbosConfig, _id, params) do
Asset.update_fbos_config!(params)
:ok
end
def update(FirmwareConfig, id, nil) do
def update(FirmwareConfig, id, nil) do
Asset.delete_firmware_config!(id)
:ok
end
def update(FirmwareConfig, _id, params) do
def update(FirmwareConfig, _id, params) do
Asset.update_firmware_config!(params)
:ok
end
# Deletion use case:
# TODO(Connor) put checks for deleting Device, FbosConfig and FirmwareConfig
@ -96,12 +97,12 @@ defmodule FarmbotCore.Asset.Command do
:ok
end
def update(FarmwareEnv, id, params) do
def update(FarmwareEnv, id, params) do
Asset.upsert_farmware_env_by_id(id, params)
:ok
end
def update(FarmwareInstallation, id, params) do
def update(FarmwareInstallation, id, params) do
Asset.upsert_farmware_manifest_by_id(id, params)
:ok
end
@ -112,15 +113,17 @@ defmodule FarmbotCore.Asset.Command do
def update(FarmEvent, id, params) do
old = Asset.get_farm_event(id)
if old,
do: Asset.update_farm_event!(old, params),
if old,
do: Asset.update_farm_event!(old, params),
else: Asset.new_farm_event!(params)
:ok
end
def update(PublicKey, id, params) do
old = Asset.get_public_key(id)
if old,
do: Asset.update_public_key!(old, params),
else: Asset.new_public_key!(params)
@ -130,33 +133,37 @@ defmodule FarmbotCore.Asset.Command do
def update(Regimen, id, params) do
old = Asset.get_regimen(id)
if old,
do: Asset.update_regimen!(old, params),
if old,
do: Asset.update_regimen!(old, params),
else: Asset.new_regimen!(params)
:ok
end
def update(Sensor, id, params) do
old = Asset.get_sensor(id)
if old,
do: Asset.update_sensor!(old, params),
if old,
do: Asset.update_sensor!(old, params),
else: Asset.new_sensor!(params)
:ok
end
def update(SensorReading, id, params) do
old = Asset.get_sensor_reading(id)
if old,
do: Asset.update_sensor_reading!(old, params),
if old,
do: Asset.update_sensor_reading!(old, params),
else: Asset.new_sensor_reading!(params)
:ok
end
def update(Sequence, id, params) do
old = Asset.get_sequence(id)
if old,
do: Asset.update_sequence!(old, params),
else: Asset.new_sequence!(params)
@ -172,6 +179,7 @@ defmodule FarmbotCore.Asset.Command do
def update(PointGroup, id, params) do
old = Asset.get_point_group(id: id)
if old,
do: Asset.update_point_group!(old, params),
else: Asset.new_point_group!(params)
@ -181,8 +189,8 @@ defmodule FarmbotCore.Asset.Command do
# Catch-all use case:
def update(asset_kind, id, params) do
Logger.warn "AssetCommand needs implementation: #{asset_kind}"
mod = as_module!(asset_kind)
case Repo.get_by(mod, id: id) do
nil ->
struct!(mod)
@ -205,28 +213,27 @@ defmodule FarmbotCore.Asset.Command do
mod.changeset(asset, params)
end
defp as_module!("Device"), do: Asset.Device
defp as_module!("DiagnosticDump"), do: Asset.DiagnosticDump
defp as_module!("FarmEvent"), do: Asset.FarmEvent
defp as_module!("FarmwareEnv"), do: Asset.FarmwareEnv
defp as_module!("FirstPartyFarmware"), do: Asset.FirstPartyFarmware
defp as_module!("FarmwareInstallation"), do: Asset.FarmwareInstallation
defp as_module!("FbosConfig"), do: Asset.FbosConfig
defp as_module!("FirmwareConfig"), do: Asset.FirmwareConfig
defp as_module!("Peripheral"), do: Asset.Peripheral
defp as_module!("PinBinding"), do: Asset.PinBinding
defp as_module!("Point"), do: Asset.Point
defp as_module!("PointGroup"), do: Asset.PointGroup
defp as_module!("Regimen"), do: Asset.Regimen
defp as_module!("Sensor"), do: Asset.Sensor
defp as_module!("SensorReading"), do: Asset.SensorReading
defp as_module!("Sequence"), do: Asset.Sequence
defp as_module!("Tool"), do: Asset.Tool
defp as_module!("Device"), do: Asset.Device
defp as_module!("FarmEvent"), do: Asset.FarmEvent
defp as_module!("FarmwareEnv"), do: Asset.FarmwareEnv
defp as_module!("FirstPartyFarmware"), do: Asset.FirstPartyFarmware
defp as_module!("FarmwareInstallation"), do: Asset.FarmwareInstallation
defp as_module!("FbosConfig"), do: Asset.FbosConfig
defp as_module!("FirmwareConfig"), do: Asset.FirmwareConfig
defp as_module!("Peripheral"), do: Asset.Peripheral
defp as_module!("PinBinding"), do: Asset.PinBinding
defp as_module!("Point"), do: Asset.Point
defp as_module!("PointGroup"), do: Asset.PointGroup
defp as_module!("Regimen"), do: Asset.Regimen
defp as_module!("Sensor"), do: Asset.Sensor
defp as_module!("SensorReading"), do: Asset.SensorReading
defp as_module!("Sequence"), do: Asset.Sequence
defp as_module!("Tool"), do: Asset.Tool
defp as_module!(module) when is_atom(module) do
as_module!(List.last(Module.split(module)))
end
defp as_module!(kind) when is_binary(kind) do
raise("""
Unknown kind: #{kind}

View File

@ -0,0 +1,183 @@
defmodule FarmbotCore.Asset.CriteriaRetriever do
alias FarmbotCore.Asset.{ PointGroup, Repo, Point }
import Ecto.Query
@moduledoc """
The PointGroup asset declares a list
of criteria to query points. This
module then converts that criteria to
a list of real points that match the
criteria of a point group.
Example:
You have a PointGroup with a criteria
where group.criteria.number_gt.x == 10
Passing that PointGroup to this module
will return an array of `Point` assets
with an x property that is greater than
10.
"""
# We will not query any string/numeric fields other than these.
# Updating the PointGroup / Point models may require an update
# to these fields.
@numberic_fields ["radius", "x", "y", "z", "pullout_direction"]
@string_fields ["name", "openfarm_slug", "plant_stage", "pointer_type"]
@doc """
You provide it a %PointGroup{},
it provides you an array of
point records (%Point{}) that match
the group's criteria.
"""
def run(%PointGroup{point_ids: static_ids} = pg) do
# pg.point_ids is *always* include in search results,
# even if it does not match pg.criteria in any way.
always_ok = Repo.all(from(p in Point, where: p.id in ^static_ids, select: p))
# Now we need a list of point IDs that actually match
# the pg.criteria fields. We only get the ID because
# we are circumventing Ecto and doing raw SQL.
# There may be better ways to do this:
dynamic_ids = find_matching_point_ids(pg)
# Once we have a list of matching criteria, we can run a
# SQL query through Ecto to return real %Point{} structs...
dynamic_query = from(p in Point, where: p.id in ^dynamic_ids, select: p)
# ...but we're not done! If the criteria contains meta fields,
# we need to perform a lookup in memory
needs_meta_filter = Repo.all(dynamic_query)
# There we go. We have all the matching %Point{}s
search_matches = search_meta_fields(pg, needs_meta_filter)
# ...but there are duplicates. We can remove them via uniq_by:
Enum.uniq_by((search_matches ++ always_ok), fn p -> p.id end)
end
@doc """
Takes intermediate search results and makes them
more specific by iterating over the search results
and only returning the ones that match the meta.*
field provided in pg.criteria
"""
def search_meta_fields(%PointGroup{} = pg, points) do
meta = "meta."
meta_len = String.length(meta)
(pg.criteria["string_eq"] || %{})
|> Map.to_list()
|> Enum.filter(fn {k, _v} ->
String.starts_with?(k, meta)
end)
|> Enum.map(fn {k, value} ->
clean_key = String.slice(k, ((meta_len)..-1))
{clean_key, value}
end)
|> Enum.reduce(%{}, fn {key, value}, all ->
all_values = all[key] || []
Map.merge(all, %{key => value ++ all_values})
end)
|> Map.to_list()
|> Enum.reduce(points, fn {key, values}, finalists ->
finalists
|> Enum.filter(fn point -> point.meta[key] end)
|> Enum.filter(fn point -> point.meta[key] in values end)
end)
end
# Find all point IDs that are matched by a PointGroup
# This is not including any meta.* search terms,
# since `meta` is a JSON column that must be
# manually searched in memory.
defp find_matching_point_ids(%PointGroup{} = pg) do
results = {pg, []}
|> stage_1("string_eq", @string_fields, "IN")
|> stage_1("number_eq", @numberic_fields, "IN")
|> stage_1("number_gt", @numberic_fields, ">")
|> stage_1("number_lt", @numberic_fields, "<")
|> stage_1_day_field()
|> unwrap_stage_1()
|> Enum.reduce(%{}, &stage_2/2)
|> Map.to_list()
|> Enum.reduce({[], [], 0}, &stage_3/2)
|> unwrap_stage_3()
|> finalize()
results
end
# EDGE CASE: If the user _only_ wants to put static points
# in their group, we need to perform 0 SQL queries.
def finalize({_, []}) do
[]
end
def finalize({fragments, criteria}) do
x = Enum.join(fragments, " AND ")
sql = "SELECT id FROM points WHERE #{x}"
query_params = List.flatten(criteria)
{:ok, query} = Repo.query(sql, query_params)
%Sqlite.DbConnection.Result{ rows: rows } = query
List.flatten(rows)
end
defp unwrap_stage_1({_, right}), do: right
defp unwrap_stage_3({query, args, _count}), do: {query, args}
defp stage_1({pg, accum}, kind, fields, op) do
results = fields
|> Enum.map(fn field -> {field, pg.criteria[kind][field]} end)
|> Enum.filter(fn {_k, v} -> v end)
|> Enum.map(fn {k, v} -> {k, op, v} end)
{pg, accum ++ results}
end
defp stage_1_day_field({pg, accum}) do
day_criteria = pg.criteria["day"] || pg.criteria[:day] || %{}
days = day_criteria["days_ago"] || day_criteria[:days_ago] || 0
op = day_criteria["op"] || day_criteria[:op] || "<"
time = Timex.shift(Timex.now(), days: -1 * days)
if days == 0 do
{ pg, accum }
else
inverted_op = if op == ">" do "<" else ">" end
{ pg, accum ++ [{"created_at", inverted_op, time}] }
end
end
defp stage_2({lhs, "IN", rhs}, results) do
query = "#{lhs} IN"
all_values = results[query] || []
Map.merge(results, %{query => rhs ++ all_values})
end
defp stage_2({lhs, op, rhs}, results) do
Map.merge(results, %{"#{lhs} #{op}" => rhs})
end
# Interpolatinng data turned out to be hard.
# Pretty sure there is an easier way to do this.
# NOT OK: Repo.query("SELECT foo WHERE bar IN $0", [[1, 2, 3]])
# OK: Repo.query("SELECT foo WHERE bar IN ($0, $1, $2)", [1, 2, 3])
defp stage_3({sql, args}, {full_query, full_args, count0}) when is_list(args) do
arg_count = Enum.count(args)
final = count0 + (arg_count - 1)
initial_state = {sql, count0}
{next_sql, _} =
if arg_count == 1 do
{sql <> " ($#{count0})", nil}
else
Enum.reduce(args, initial_state, fn
(_, {sql, ^count0}) -> {sql <> " ($#{count0},", count0+1}
(_, {sql, ^final}) -> {sql <> " $#{final})", final}
(_, {sql, count}) -> {sql <> " $#{count},", count+1}
end)
end
{full_query ++ [next_sql], full_args ++ [args], final + 1}
end
defp stage_3({sql, args}, {full_query, full_args, count}) do
{full_query ++ [sql <> " $#{count}"], full_args ++ [args], count + 1}
end
end

View File

@ -1,58 +0,0 @@
defmodule FarmbotCore.Asset.DiagnosticDump do
@moduledoc """
Just the DiagDump REST resource, used by FarmBot staff to help users debug
remote device problems.
"""
use FarmbotCore.Asset.Schema, path: "/api/diagnostic_dumps"
schema "diagnostic_dumps" do
field(:id, :id)
has_one(:local_meta, FarmbotCore.Asset.Private.LocalMeta,
on_delete: :delete_all,
references: :local_id,
foreign_key: :asset_local_id
)
field(:ticket_identifier, :string)
field(:fbos_commit, :string)
field(:fbos_version, :string)
field(:firmware_commit, :string)
field(:firmware_state, :string)
field(:network_interface, :string)
field(:fbos_dmesg_dump, :string)
field(:monitor, :boolean, default: true)
timestamps()
end
view diagnostic_dump do
%{
id: diagnostic_dump.id,
ticket_identifier: diagnostic_dump.ticket_identifier,
fbos_commit: diagnostic_dump.fbos_commit,
fbos_version: diagnostic_dump.fbos_version,
firmware_commit: diagnostic_dump.firmware_commit,
firmware_state: diagnostic_dump.firmware_state,
network_interface: diagnostic_dump.network_interface,
fbos_dmesg_dump: diagnostic_dump.fbos_dmesg_dump
}
end
def changeset(diagnostic_dump, params \\ %{}) do
diagnostic_dump
|> cast(params, [
:id,
:ticket_identifier,
:fbos_commit,
:fbos_version,
:firmware_commit,
:firmware_state,
:network_interface,
:fbos_dmesg_dump,
:monitor,
:created_at,
:updated_at
])
|> validate_required([])
end
end

View File

@ -100,16 +100,15 @@ defimpl String.Chars, for: FarmbotCore.Asset.PinBinding do
end
defp special_action(button_number, action, pin_num) do
"Button #{button_number}: #{format_action(action)} (Pi #{pin_num})"
"Button #{button_number}: #{format_action(action)} (Pi #{pin_num})"
end
defp format_action("dump_info"), do: "Dump Info"
defp format_action("emergency_lock"), do: "E-Stop"
defp format_action("emergency_lock"), do: "E-Stop"
defp format_action("emergency_unlock"), do: "E-Unlock"
defp format_action("power_off"), do: "Power Off"
defp format_action("read_status"), do: "Read Status"
defp format_action("reboot"), do: "Reboot"
defp format_action("sync"), do: "Sync"
defp format_action("take_photo"), do: "Take Photo"
defp format_action("take_photo"), do: "Take Photo"
defp format_action(_), do: nil
end

View File

@ -13,18 +13,21 @@ defmodule FarmbotCore.Asset.Point do
foreign_key: :asset_local_id
)
field(:discarded_at, :utc_datetime)
field(:gantry_mounted, :boolean)
field(:meta, :map)
field(:monitor, :boolean, default: true)
field(:name, :string)
field(:openfarm_slug, :string)
field(:plant_stage, :string)
field(:planted_at, :utc_datetime)
field(:pointer_type, :string)
field(:pullout_direction, :integer)
field(:radius, :float)
field(:tool_id, :integer)
field(:x, :float)
field(:y, :float)
field(:z, :float)
field(:tool_id, :integer)
field(:discarded_at, :utc_datetime)
field(:monitor, :boolean, default: true)
timestamps()
end
@ -34,11 +37,15 @@ defmodule FarmbotCore.Asset.Point do
meta: point.meta,
name: point.name,
plant_stage: point.plant_stage,
created_at: point.created_at,
planted_at: point.planted_at,
pointer_type: point.pointer_type,
radius: point.radius,
tool_id: point.tool_id,
discarded_at: point.discarded_at,
gantry_mounted: point.gantry_mounted,
openfarm_slug: point.openfarm_slug,
pullout_direction: point.pullout_direction,
x: point.x,
y: point.y,
z: point.z
@ -48,21 +55,24 @@ defmodule FarmbotCore.Asset.Point do
def changeset(point, params \\ %{}) do
point
|> cast(params, [
:created_at,
:discarded_at,
:gantry_mounted,
:id,
:meta,
:monitor,
:name,
:plant_stage,
:planted_at,
:pointer_type,
:pullout_direction,
:openfarm_slug,
:radius,
:tool_id,
:updated_at,
:x,
:y,
:z,
:tool_id,
:discarded_at,
:monitor,
:created_at,
:updated_at
])
|> validate_required([])
end

View File

@ -5,6 +5,18 @@ defmodule FarmbotCore.Asset.PointGroup do
use FarmbotCore.Asset.Schema, path: "/api/point_groups"
@default_criteria %{
"day" => %{ "op" => ">", "days_ago" => 0 },
# Map<string, string[] | undefined>,
"string_eq" => %{},
# Map<string, number[] | undefined>,
"number_eq" => %{},
# Map<string, number | undefined>,
"number_lt" => %{},
# Map<string, number | undefined>,
"number_gt" => %{},
}
schema "point_groups" do
field(:id, :id)
@ -17,6 +29,7 @@ defmodule FarmbotCore.Asset.PointGroup do
field(:name, :string)
field(:point_ids, {:array, :integer})
field(:sort_type, :string)
field(:criteria, :map, default: @default_criteria)
field(:monitor, :boolean, default: true)
timestamps()
@ -27,13 +40,23 @@ defmodule FarmbotCore.Asset.PointGroup do
id: point_group.id,
name: point_group.name,
point_ids: point_group.point_ids,
sort_type: point_group.sort_type
sort_type: point_group.sort_type,
criteria: point_group.criteria
}
end
def changeset(point_group, params \\ %{}) do
point_group
|> cast(params, [:id, :name, :point_ids, :sort_type, :monitor, :created_at, :updated_at])
|> cast(params, [
:id,
:name,
:criteria,
:point_ids,
:sort_type,
:monitor,
:created_at,
:updated_at
])
|> validate_required([])
end
end

View File

@ -40,17 +40,17 @@ defmodule FarmbotCore.Asset.Private do
# Because sqlite can't test unique constraints before a transaction, if this function gets called for
# the same asset more than once asyncronously, the asset can be marked dirty twice at the same time
# causing the `unique constraint` error to happen in either `ecto` OR `sqlite`. I've
# caught both errors here as they are both essentially the same thing, and can be safely
# caught both errors here as they are both essentially the same thing, and can be safely
# discarded. Doing an `insert_or_update/1` (without the bang) can still result in the sqlite
# error being thrown.
# error being thrown.
changeset = LocalMeta.changeset(local_meta, Map.merge(params, %{table: table, status: "dirty"}))
try do
Repo.insert_or_update!(changeset)
catch
:error, %Sqlite.DbConnection.Error{
message: "UNIQUE constraint failed: local_metas.table, local_metas.asset_local_id",
message: "UNIQUE constraint failed: local_metas.table, local_metas.asset_local_id",
sqlite: %{code: :constraint}
} ->
} ->
Logger.warn """
Caught race condition marking data as dirty (sqlite)
table: #{inspect(table)}
@ -59,10 +59,10 @@ defmodule FarmbotCore.Asset.Private do
Ecto.Changeset.apply_changes(changeset)
:error, %Ecto.InvalidChangesetError{
changeset: %{
action: :insert,
action: :insert,
errors: [
table: {"LocalMeta already exists.", [
validation: :unsafe_unique,
validation: :unsafe_unique,
fields: [:table, :asset_local_id]
]}
]}
@ -73,7 +73,7 @@ defmodule FarmbotCore.Asset.Private do
id: #{inspect(asset.local_id)}
"""
Ecto.Changeset.apply_changes(changeset)
type, reason ->
type, reason ->
FarmbotCore.Logger.error 1, """
Caught unexpected error marking data as dirty
table: #{inspect(table)}

View File

@ -9,7 +9,6 @@ defmodule FarmbotCore.Asset.Private.LocalMeta do
alias FarmbotCore.Asset.{
Repo,
Device,
DiagnosticDump,
DeviceCert,
FarmEvent,
FarmwareEnv,
@ -47,13 +46,6 @@ defmodule FarmbotCore.Asset.Private.LocalMeta do
define_field: false
)
belongs_to(:diagnostic_dump, DiagnosticDump,
foreign_key: :asset_local_id,
type: :binary_id,
references: :local_id,
define_field: false
)
belongs_to(:farm_event, FarmEvent,
foreign_key: :asset_local_id,
type: :binary_id,
@ -174,8 +166,7 @@ defmodule FarmbotCore.Asset.Private.LocalMeta do
"firmware_configs",
"fbos_configs",
"farmware_installations",
"farmware_envs",
"diagnostic_dumps"
"farmware_envs"
])
|> unsafe_validate_unique([:table, :asset_local_id], Repo,
message: "LocalMeta already exists."

View File

@ -23,7 +23,11 @@ defmodule FarmbotCore.Asset.Supervisor do
end
def init([]) do
children = [
Supervisor.init(children(), strategy: :one_for_one)
end
def children do
default = [
Repo,
{AssetSupervisor, module: FbosConfig},
{AssetSupervisor, module: FirmwareConfig},
@ -38,7 +42,7 @@ defmodule FarmbotCore.Asset.Supervisor do
{AssetSupervisor, module: FarmwareEnv},
AssetMonitor,
]
Supervisor.init(children, strategy: :one_for_one)
config = Application.get_env(:farmbot_ext, __MODULE__) || []
Keyword.get(config, :children, default)
end
end

View File

@ -41,7 +41,6 @@ defmodule FarmbotCore.Asset.Sync do
embeds_many(:devices, Item)
embeds_many(:firmware_configs, Item)
embeds_many(:fbos_configs, Item)
embeds_many(:diagnostic_dumps, Item)
embeds_many(:farm_events, Item)
embeds_many(:farmware_envs, Item)
embeds_many(:first_party_farmwares, Item)
@ -65,7 +64,6 @@ defmodule FarmbotCore.Asset.Sync do
devices: Enum.map(sync.device, &Item.render/1),
fbos_configs: Enum.map(sync.fbos_config, &Item.render/1),
firmware_configs: Enum.map(sync.firmware_config, &Item.render/1),
diagnostic_dumps: Enum.map(sync.diagnostic_dumps, &Item.render/1),
farm_events: Enum.map(sync.farm_events, &Item.render/1),
farmware_envs: Enum.map(sync.farmware_envs, &Item.render/1),
first_party_farmwares: Enum.map(sync.first_party_farmwares, &Item.render/1),
@ -90,7 +88,6 @@ defmodule FarmbotCore.Asset.Sync do
|> cast_embed(:devices)
|> cast_embed(:fbos_configs)
|> cast_embed(:firmware_configs)
|> cast_embed(:diagnostic_dumps)
|> cast_embed(:farm_events)
|> cast_embed(:farmware_envs)
|> cast_embed(:farmware_installations)

View File

@ -1,25 +1,26 @@
defmodule FarmbotCore.AssetHelpers do
@moduledoc """
Helpers for the console at runtime.
Example:
iex()> use FarmbotCore.AssetHelpers
iex()> Repo.all(Device)
[%Device{}]
"""
@doc false
defmacro __using__(_opts) do
require Logger
Logger.warn "Don't use this in production please!"
Logger.warn("Don't use this in production please!")
quote do
import Ecto.Query
alias FarmbotCore.Asset
alias Asset.{
Repo,
Device,
DeviceCert,
DiagnosticDump,
FarmwareEnv,
FarmwareInstallation,
FirstPartyFarmware,
@ -40,4 +41,4 @@ defmodule FarmbotCore.AssetHelpers do
}
end
end
end
end

View File

@ -82,7 +82,6 @@ defmodule FarmbotCore.AssetMonitor do
sub_state = Map.drop(sub_state, deleted_ids)
Enum.each(deleted_ids, fn local_id ->
Logger.error("#{inspect(kind)} #{local_id} needs to be terminated")
AssetSupervisor.terminate_child(kind, local_id)
end)
@ -94,13 +93,11 @@ defmodule FarmbotCore.AssetMonitor do
Map.put(sub_state, id, updated_at)
is_nil(sub_state[id]) ->
Logger.debug("#{inspect(kind)} #{id} needs to be started")
asset = Repo.preload(asset, AssetWorker.preload(asset))
:ok = AssetSupervisor.start_child(asset) |> assert_result!(asset)
Map.put(sub_state, id, updated_at)
compare_datetimes(updated_at, sub_state[id]) == :gt ->
Logger.warn("#{inspect(kind)} #{id} needs to be updated")
asset = Repo.preload(asset, AssetWorker.preload(asset))
:ok = AssetSupervisor.update_child(asset) |> assert_result!(asset)
Map.put(sub_state, id, updated_at)

View File

@ -66,9 +66,9 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Device do
{:mounted_tool_id, nil} ->
if old_device.mounted_tool_id do
if tool = Asset.get_tool(id: old_device.mounted_tool_id) do
FarmbotCore.Logger.info(2, "Farmbot dismounted #{tool.name}")
FarmbotCore.Logger.info(2, "Dismounted the #{tool.name}")
else
FarmbotCore.Logger.info(2, "Farmbot dismounted unknown tool")
FarmbotCore.Logger.info(2, "Dismounted unknown tool")
end
else
# no previously mounted tool
@ -77,9 +77,9 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Device do
{:mounted_tool_id, id} ->
if tool = Asset.get_tool(id: id) do
FarmbotCore.Logger.info(2, "Farmbot mounted #{tool.name}")
FarmbotCore.Logger.info(2, "Mounted the #{tool.name}")
else
FarmbotCore.Logger.info(2, "Farmbot mounted unknown tool")
FarmbotCore.Logger.info(2, "Mounted unknown tool")
end
{_key, _value} ->

View File

@ -11,16 +11,9 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.FbosConfig do
alias FarmbotCore.{Asset.FbosConfig, BotState, Config}
import FarmbotFirmware.PackageUtils, only: [package_to_string: 1]
@firmware_flash_attempt_threshold Application.get_env(:farmbot_core, __MODULE__)[:firmware_flash_attempt_threshold]
@firmware_flash_attempt_threshold Application.get_env(:farmbot_core, __MODULE__)[:firmware_flash_attempt_threshold] || 5
@firmware_flash_timeout Application.get_env(:farmbot_core, __MODULE__)[:firmware_flash_timeout] || 5000
@disable_firmware_io_logs_timeout Application.get_env(:farmbot_core, __MODULE__)[:disable_firmware_io_logs_timeout] || 300000
@firmware_flash_attempt_threshold || Mix.raise """
Firmware open attempt threshold not configured:
config :farmbot_core, #{__MODULE__}, [
firmware_flash_attempt_threshold: :infinity
]
"""
@impl FarmbotCore.AssetWorker
def preload(%FbosConfig{}), do: []

View File

@ -33,7 +33,7 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Peripheral do
{:noreply, state}
end
def handle_info(:timeout, %{fw_version: "8.0.0.S"} = state) do
def handle_info(:timeout, %{fw_version: "8.0.0.S.stub"} = state) do
{:noreply, state}
end
@ -47,15 +47,15 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Peripheral do
Logger.debug("Read peripheral: #{peripheral.label}")
rpc = peripheral_to_rpc(peripheral)
case FarmbotCeleryScript.execute(rpc, make_ref()) do
:ok ->
:ok ->
Logger.debug("Read peripheral: #{peripheral.label} ok")
{:noreply, state}
{:error, reason} when errors < 5 ->
{:error, reason} when errors < 5 ->
Logger.error("Read peripheral: #{peripheral.label} error: #{reason} errors=#{state.errors}")
Process.send_after(self(), :timeout, @retry_ms)
{:noreply, %{state | errors: state.errors + 1}}
{:error, reason} when errors == 5 ->
Logger.error("Read peripheral: #{peripheral.label} error: #{reason} errors=5 not trying again.")
{:noreply, state}

View File

@ -3,12 +3,12 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.PinBinding do
Worker for monitoring hardware GPIO. (not related to the mcu firmware.)
Upon a button trigger, a `sequence`, or `special_action` will be executed by
the CeleryScript Runtime.
the CeleryScript Runtime.
This module also defines a behaviour that allows for abstracting and testing
This module also defines a behaviour that allows for abstracting and testing
independent of GPIO hardware code.
"""
use GenServer
require Logger
require FarmbotCore.Logger
@ -75,6 +75,7 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.PinBinding do
case Asset.get_sequence(pin_binding.sequence_id) do
%Sequence{name: name} = seq ->
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing #{name}")
AST.decode(seq)
|> execute(state)
@ -84,24 +85,24 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.PinBinding do
end
end
def handle_cast(:trigger, %{pin_binding: %{special_action: "dump_info"} = pin_binding} = state) do
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing Dump Info")
AST.Factory.new()
|> AST.Factory.rpc_request("pin_binding.#{pin_binding.pin_num}")
|> AST.Factory.dump_info()
|> execute(state)
end
def handle_cast(:trigger, %{pin_binding: %{special_action: "emergency_lock"} = pin_binding} = state) do
def handle_cast(
:trigger,
%{pin_binding: %{special_action: "emergency_lock"} = pin_binding} = state
) do
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing Emergency Lock")
AST.Factory.new()
|> AST.Factory.rpc_request("pin_binding.#{pin_binding.pin_num}")
|> AST.Factory.emergency_lock()
|> execute(state)
end
end
def handle_cast(:trigger, %{pin_binding: %{special_action: "emergency_unlock"} = pin_binding} = state) do
def handle_cast(
:trigger,
%{pin_binding: %{special_action: "emergency_unlock"} = pin_binding} = state
) do
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing Emergency Unlock")
AST.Factory.new()
|> AST.Factory.rpc_request("pin_binding.#{pin_binding.pin_num}")
|> AST.Factory.emergency_unlock()
@ -110,14 +111,19 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.PinBinding do
def handle_cast(:trigger, %{pin_binding: %{special_action: "power_off"} = pin_binding} = state) do
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing Power Off")
AST.Factory.new()
|> AST.Factory.rpc_request("pin_binding.#{pin_binding.pin_num}")
|> AST.Factory.power_off()
|> execute(state)
end
def handle_cast(:trigger, %{pin_binding: %{special_action: "read_status"} = pin_binding} = state) do
def handle_cast(
:trigger,
%{pin_binding: %{special_action: "read_status"} = pin_binding} = state
) do
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing Read Status")
AST.Factory.new()
|> AST.Factory.rpc_request("pin_binding.#{pin_binding.pin_num}")
|> AST.Factory.read_status()
@ -126,6 +132,7 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.PinBinding do
def handle_cast(:trigger, %{pin_binding: %{special_action: "reboot"} = pin_binding} = state) do
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing Reboot")
AST.Factory.new()
|> AST.Factory.rpc_request("pin_binding.#{pin_binding.pin_num}")
|> AST.Factory.reboot()
@ -134,6 +141,7 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.PinBinding do
def handle_cast(:trigger, %{pin_binding: %{special_action: "sync"} = pin_binding} = state) do
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing Sync")
AST.Factory.new()
|> AST.Factory.rpc_request("pin_binding.#{pin_binding.pin_num}")
|> AST.Factory.sync()
@ -142,6 +150,7 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.PinBinding do
def handle_cast(:trigger, %{pin_binding: %{special_action: "take_photo"} = pin_binding} = state) do
FarmbotCore.Logger.info(1, "#{pin_binding} triggered, executing Take Photo")
AST.Factory.new()
|> AST.Factory.rpc_request("pin_binding.#{pin_binding.pin_num}")
|> AST.Factory.take_photo()
@ -182,10 +191,13 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.PinBinding do
defp execute(%AST{} = ast, state) do
case FarmbotCeleryScript.execute(ast, make_ref()) do
:ok -> :ok
:ok ->
:ok
{:error, reason} ->
FarmbotCore.Logger.error 1, "error executing #{state.pin_binding}: #{reason}"
FarmbotCore.Logger.error(1, "error executing #{state.pin_binding}: #{reason}")
end
{:noreply, state}
end

View File

@ -25,8 +25,6 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.RegimenInstance do
@impl GenServer
def init([regimen_instance, _args]) do
Logger.warn "RegimenInstance #{inspect(regimen_instance)} initializing"
with %Regimen{} <- regimen_instance.regimen,
%FarmEvent{} <- regimen_instance.farm_event do
send self(), :schedule
@ -40,25 +38,25 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.RegimenInstance do
def handle_info(:schedule, state) do
regimen_instance = state.regimen_instance
# load the sequence and calculate the scheduled_at time
Enum.map(regimen_instance.regimen.regimen_items, fn(%{time_offset: offset, sequence_id: sequence_id}) ->
Enum.map(regimen_instance.regimen.regimen_items, fn(%{time_offset: offset, sequence_id: sequence_id}) ->
scheduled_at = DateTime.add(regimen_instance.epoch, offset, :millisecond)
sequence = Asset.get_sequence(sequence_id) || raise("sequence #{sequence_id} is not synced")
%{scheduled_at: scheduled_at, sequence: sequence}
end)
# get rid of any item that has already been scheduled/executed
|> Enum.reject(fn(%{scheduled_at: scheduled_at}) ->
|> Enum.reject(fn(%{scheduled_at: scheduled_at}) ->
Asset.get_regimen_instance_execution(regimen_instance, scheduled_at)
end)
|> Enum.each(fn(%{scheduled_at: at, sequence: sequence}) ->
|> Enum.each(fn(%{scheduled_at: at, sequence: sequence}) ->
schedule_sequence(regimen_instance, sequence, at)
end)
{:noreply, state}
{:noreply, state}
end
def handle_info({FarmbotCeleryScript, {:scheduled_execution, scheduled_at, executed_at, result}}, state) do
status = case result do
:ok -> "ok"
{:error, reason} ->
{:error, reason} ->
FarmbotCore.Logger.error(2, "Regimen scheduled at #{scheduled_at} failed to execute: #{reason}")
reason
end
@ -81,11 +79,11 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.RegimenInstance do
regimen_params = AST.decode(regimen_instance.regimen.body)
# there may be many sequence scopes from here downward
celery_ast = AST.decode(sequence)
celery_args =
celery_args =
celery_ast.args
|> Map.put(:sequence_name, sequence.name)
|> Map.put(:locals, %{celery_ast.args.locals | body: celery_ast.args.locals.body ++ regimen_params ++ farm_event_params})
celery_ast = %{celery_ast | args: celery_args}
FarmbotCeleryScript.schedule(celery_ast, at, sequence)
end

View File

@ -1,6 +1,8 @@
defmodule FarmbotCore.BotState do
@moduledoc "Central State accumulator."
alias FarmbotCore.BotStateNG
alias FarmbotCore.BotState.JobProgress.Percent
require FarmbotCore.Logger
use GenServer
@ -28,7 +30,7 @@ defmodule FarmbotCore.BotState do
def set_position(bot_state_server \\ __MODULE__, x, y, z) do
GenServer.call(bot_state_server, {:set_position, x, y, z})
end
@doc "Sets the location_data.load"
def set_load(bot_state_server \\ __MODULE__, x, y, z) do
GenServer.call(bot_state_server, {:set_load, x, y, z})
@ -161,6 +163,10 @@ defmodule FarmbotCore.BotState do
GenServer.call(bot_state_server, :enter_maintenance_mode)
end
def job_in_progress?(job_name, bot_state_server \\ __MODULE__) do
GenServer.call(bot_state_server, {:job_in_progress?, job_name})
end
@doc false
def start_link(args, opts \\ [name: __MODULE__]) do
GenServer.start_link(__MODULE__, args, opts)
@ -175,6 +181,13 @@ defmodule FarmbotCore.BotState do
FarmbotCore.Logger.error 1, "BotState crashed! #{inspect(reason)}"
end
def handle_call({:job_in_progress?, job_name}, _from, state) do
progress = (state.tree.jobs[job_name] || %Percent{}).percent
in_progress? = (progress > 0.0 && progress < 100.0)
{:reply, in_progress?, state}
end
@doc false
def handle_call(:subscribe, {pid, _} = _from, state) do
# TODO Just replace this with Elixir.Registry?

View File

@ -6,11 +6,16 @@ defmodule FarmbotCore.BotState.Supervisor do
end
def init([]) do
children = [
Supervisor.init(children(), [strategy: :one_for_all])
end
def children do
default = [
FarmbotCore.BotState,
FarmbotCore.BotState.FileSystem,
FarmbotCore.BotState.SchedulerUsageReporter
]
Supervisor.init(children, [strategy: :one_for_all])
config = Application.get_env(:farmbot_ext, __MODULE__) || []
Keyword.get(config, :children, default)
end
end

View File

@ -13,7 +13,7 @@ defmodule FarmbotCore.BotStateNG.LocationData.Vec3 do
def new do
%__MODULE__{}
|> changeset(%{x: -1, y: -1, z: -1})
|> changeset(%{x: nil, y: nil, z: nil})
|> apply_changes()
end
@ -29,4 +29,4 @@ defmodule FarmbotCore.BotStateNG.LocationData.Vec3 do
vec3
|> cast(params, [:x, :y, :z])
end
end
end

View File

@ -210,7 +210,7 @@ defmodule FarmbotCore.BotStateNG.McuParams do
pin_guard_4_active_state: mcu_params.pin_guard_4_active_state,
pin_guard_5_pin_nr: mcu_params.pin_guard_5_pin_nr,
pin_guard_5_time_out: mcu_params.pin_guard_5_time_out,
pin_guard_5_active_state: :pin_guard_5_active_stat
pin_guard_5_active_state: mcu_params.pin_guard_5_active_state
}
end

View File

@ -7,9 +7,12 @@ defmodule FarmbotCore.Config.Supervisor do
end
def init([]) do
children = [
{FarmbotCore.Config.Repo, []},
]
Supervisor.init(children, strategy: :one_for_one)
Supervisor.init(children(), strategy: :one_for_one)
end
def children do
default = [ {FarmbotCore.Config.Repo, []} ]
config = Application.get_env(:farmbot_ext, __MODULE__) || []
Keyword.get(config, :children, default)
end
end

View File

@ -4,10 +4,10 @@ defmodule FarmbotCore.FarmwareRuntime do
"""
alias FarmbotCeleryScript.AST
alias FarmbotCore.FarmwareRuntime.PipeWorker
alias FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmwareInstallation
alias FarmbotCore.Asset.FarmwareInstallation.Manifest
alias FarmbotCore.AssetWorker.FarmbotCore.Asset.FarmwareInstallation
alias FarmbotCore.BotState.FileSystem
alias FarmbotCore.FarmwareRuntime.PipeWorker
alias FarmbotCore.Project
import FarmwareInstallation, only: [install_dir: 1]
@ -67,7 +67,8 @@ defmodule FarmbotCore.FarmwareRuntime do
@doc "Stop a farmware"
def stop(pid) do
Logger.info "Terminating farmware process"
Logger.info("Terminating farmware process")
if Process.alive?(pid) do
GenServer.stop(pid, :normal)
end
@ -75,7 +76,7 @@ defmodule FarmbotCore.FarmwareRuntime do
def init([manifest, env, caller]) do
package = manifest.package
<<clause1 :: binary-size(8), _::binary>> = Ecto.UUID.generate()
<<clause1::binary-size(8), _::binary>> = Ecto.UUID.generate()
request_pipe =
Path.join([
@ -109,7 +110,8 @@ defmodule FarmbotCore.FarmwareRuntime do
)
# Start the plugin.
Logger.debug "spawning farmware: #{exec} #{manifest.args}"
Logger.debug("spawning farmware: #{exec} #{manifest.args}")
{cmd, _} = spawn_monitor(MuonTrap, :cmd, ["sh", ["-c", "#{exec} #{manifest.args}"], opts])
state = %State{
@ -125,7 +127,7 @@ defmodule FarmbotCore.FarmwareRuntime do
response_pipe_handle: resp
}
send self(), :timeout
send(self(), :timeout)
{:ok, state}
end
@ -142,24 +144,23 @@ defmodule FarmbotCore.FarmwareRuntime do
end
def handle_info(msg, %{context: :error} = state) do
Logger.warn "unhandled message in error state: #{inspect(msg)}"
Logger.warn("unhandled message in error state: #{inspect(msg)}")
{:noreply, state}
end
def handle_info({:step_complete, ref, {:error, reason}}, %{scheduler_ref: ref} = state) do
send state.caller, {:error, reason}
send(state.caller, {:error, reason})
{:noreply, %{state | ref: nil, context: :error}}
end
def handle_info({:step_complete, ref, :ok}, %{scheduler_ref: ref} = state) do
label = UUID.uuid4()
result = %AST{kind: :rpc_ok, args: %{label: label}, body: []}
result = %AST{kind: :rpc_ok, args: %{label: state.rpc.args.label}, body: []}
ipc = add_header(result)
_reply = PipeWorker.write(state.response_pipe_handle, ipc)
# Make sure to `timeout` after this one to go back to the
# get_header context. This will cause another rpc to be processed.
send self(), :timeout
send(self(), :timeout)
{:noreply, %{state | rpc: nil, context: :get_header}}
end
@ -174,14 +175,14 @@ defmodule FarmbotCore.FarmwareRuntime do
# didn't pick up the scheduled AST in a reasonable amount of time.
def handle_info(:timeout, %{context: :process_request} = state) do
Logger.error("Timeout waiting for #{inspect(state.rpc)} to be processed")
send state.caller, {:error, :rpc_timeout}
send(state.caller, {:error, :rpc_timeout})
{:noreply, %{state | context: :error}}
end
# farmware exit
def handle_info({:DOWN, _ref, :process, _pid, _reason}, %{cmd: _cmd_pid} = state) do
Logger.debug("Farmware exit")
send state.caller, {:error, :farmware_exit}
send(state.caller, {:error, :farmware_exit})
{:noreply, %{state | context: :error}}
end
@ -200,14 +201,14 @@ defmodule FarmbotCore.FarmwareRuntime do
# error result of an io:read/2 in :get_header context
def handle_info({PipeWorker, _ref, {:ok, data}}, %{context: :get_header} = state) do
Logger.error("Bad header: #{inspect(data, base: :hex, limit: :infinity)}")
send state.caller, {:error, {:unhandled_packet, data}}
send(state.caller, {:error, {:unhandled_packet, data}})
{:noreply, %{state | context: :error}}
end
# error result of an io:read/2 in :get_header context
def handle_info({PipeWorker, _ref, error}, %{context: :get_header} = state) do
Logger.error("Bad header: #{inspect(error)}")
send state.caller, {:error, :bad_packet_header}
send(state.caller, {:error, :bad_packet_header})
{:noreply, %{state | context: :error}}
end
@ -219,7 +220,7 @@ defmodule FarmbotCore.FarmwareRuntime do
# error result of an io:read/2 in :get_header context
def handle_info({PipeWorker, _ref, error}, %{context: :get_payload} = state) do
Logger.error("Bad payload: #{inspect(error)}")
send state.caller, {:error, :bad_packet_payload}
send(state.caller, {:error, :bad_packet_payload})
{:noreply, %{state | context: :error}}
end
@ -247,10 +248,12 @@ defmodule FarmbotCore.FarmwareRuntime do
Logger.debug("executing rpc from farmware: #{inspect(rpc)}")
# todo(connor) replace this with StepRunner?
FarmbotCeleryScript.execute(rpc, ref)
{:noreply, %{state | rpc: rpc, scheduler_ref: ref, context: :process_request}, @error_timeout_ms}
{:noreply, %{state | rpc: rpc, scheduler_ref: ref, context: :process_request},
@error_timeout_ms}
else
{:error, reason} ->
send state.caller, {:error, reason}
send(state.caller, {:error, reason})
{:noreply, %{state | context: :error}}
end
end
@ -300,6 +303,7 @@ defmodule FarmbotCore.FarmwareRuntime do
header =
<<@packet_header_token::size(16)>> <>
:binary.copy(<<0x00>>, 4) <> <<byte_size(payload)::big-size(32)>>
header <> payload
end
end

View File

@ -9,14 +9,7 @@ defmodule FarmbotCore.FirmwareOpenTask do
require FarmbotCore.Logger
alias FarmbotFirmware.{UARTTransport, StubTransport}
alias FarmbotCore.{Asset, Config}
@attempt_threshold Application.get_env(:farmbot_core, __MODULE__)[:attempt_threshold]
@attempt_threshold || Mix.raise """
Firmware open attempt threshold not configured:
config :farmbot_core, FarmbotCore.FirmwareOpenTask, [
attempt_threshold: 10
]
"""
@attempt_threshold Application.get_env(:farmbot_core, __MODULE__)[:attempt_threshold] || 5
@doc false
def start_link(args, opts \\ [name: __MODULE__]) do
@ -25,7 +18,10 @@ defmodule FarmbotCore.FirmwareOpenTask do
@doc false
def swap_transport(tty) do
Application.put_env(:farmbot_firmware, FarmbotFirmware, transport: UARTTransport, device: tty)
Application.put_env(:farmbot_firmware, FarmbotFirmware,
transport: UARTTransport,
device: tty,
reset: FarmbotCore.FirmwareResetter)
# Swap transport on FW module.
# Close tranpsort if it is open currently.
_ = FarmbotFirmware.close_transport()
@ -33,7 +29,9 @@ defmodule FarmbotCore.FirmwareOpenTask do
end
def unswap_transport() do
Application.put_env(:farmbot_firmware, FarmbotFirmware, transport: StubTransport)
Application.put_env(:farmbot_firmware, FarmbotFirmware,
transport: StubTransport,
reset: FarmbotCore.FirmwareResetter)
# Swap transport on FW module.
# Close tranpsort if it is open currently.
_ = FarmbotFirmware.close_transport()
@ -77,21 +75,21 @@ defmodule FarmbotCore.FirmwareOpenTask do
{:noreply, increment_attempts(%{state | timer: timer})}
firmware_hardware == "none" && needs_open? ->
FarmbotCore.Logger.debug 3, "Firmware needs to be closed"
FarmbotCore.Logger.debug 3, "Closing firmware..."
unswap_transport()
Config.update_config_value(:bool, "settings", "firmware_needs_open", false)
timer = Process.send_after(self(), :open, 5000)
{:noreply, %{state | timer: timer, attempts: 0}}
needs_open? ->
FarmbotCore.Logger.debug 3, "Firmware needs to be opened"
FarmbotCore.Logger.debug 3, "Opening firmware..."
case swap_transport(firmware_path) do
:ok ->
Config.update_config_value(:bool, "settings", "firmware_needs_open", false)
timer = Process.send_after(self(), :open, 5000)
{:noreply, %{state | timer: timer, attempts: 0}}
_ ->
FarmbotCore.Logger.debug 3, "Firmware failed to open"
other ->
FarmbotCore.Logger.debug 3, "Not ready to open yet, will retry in 5s (#{inspect(other)})"
timer = Process.send_after(self(), :open, 5000)
{:noreply, %{state | timer: timer, attempts: 0}}
end

View File

@ -0,0 +1,46 @@
defmodule FarmbotCore.FirmwareResetter do
if Code.ensure_compiled?(Circuits.GPIO) do
@gpio Circuits.GPIO
else
@gpio nil
end
alias FarmbotCore.Asset
require FarmbotCore.Logger
def reset(package \\ nil) do
pkg = package || Asset.fbos_config(:firmware_hardware)
FarmbotCore.Logger.debug(3, "Attempting to retrieve #{pkg} reset function.")
{:ok, fun} = find_reset_fun(pkg)
fun.()
end
def find_reset_fun("express_k10") do
FarmbotCore.Logger.debug(3, "Using special express reset function")
{:ok, fn -> express_reset_fun() end}
end
def find_reset_fun(_) do
FarmbotCore.Logger.debug(3, "Using default reset function")
{:ok, fn -> :ok end}
end
def express_reset_fun() do
try do
gpio_module = @gpio
FarmbotCore.Logger.debug(3, "Begin MCU reset")
{:ok, gpio} = gpio_module.open(19, :output)
:ok = gpio_module.write(gpio, 0)
:ok = gpio_module.write(gpio, 1)
Process.sleep(1000)
:ok = gpio_module.write(gpio, 0)
FarmbotCore.Logger.debug(3, "Finish MCU Reset")
:ok
rescue
ex ->
message = Exception.message(ex)
msg = "Express reset failed #{message}"
FarmbotCore.Logger.error(3, msg)
{:error, msg}
end
end
end

View File

@ -16,7 +16,14 @@ defmodule FarmbotCore.FirmwareSideEffects do
end
@impl FarmbotFirmware.SideEffects
def handle_position_change([{_axis, _value}]) do
def handle_position_change([{axis, 0.0}]) do
FarmbotCore.Logger.warn(1, "#{axis}-axis stopped at home")
:noop
end
@impl FarmbotFirmware.SideEffects
def handle_position_change([{axis, _}]) do
FarmbotCore.Logger.warn(1, "#{axis}-axis stopped at maximum")
:noop
end
@ -27,7 +34,7 @@ defmodule FarmbotCore.FirmwareSideEffects do
@impl FarmbotFirmware.SideEffects
def handle_axis_timeout(axis) do
FarmbotCore.Logger.error 1, "Axis #{axis} timed out waiting for movement to complete"
FarmbotCore.Logger.error(1, "#{axis}-axis timed out waiting for movement to complete")
:noop
end
@ -48,7 +55,7 @@ defmodule FarmbotCore.FirmwareSideEffects do
# this is a bug in the firmware code i think
def handle_encoders_scaled([]), do: :noop
@impl FarmbotFirmware.SideEffects
def handle_encoders_raw(x: x, y: y, z: z) do
:ok = BotState.set_encoders_raw(x, y, z)
@ -64,6 +71,7 @@ defmodule FarmbotCore.FirmwareSideEffects do
%{param => value}
|> Asset.update_firmware_config!()
|> Asset.Private.mark_dirty!(%{})
:ok
end
@ -75,31 +83,56 @@ defmodule FarmbotCore.FirmwareSideEffects do
@impl FarmbotFirmware.SideEffects
def handle_software_version([version]) do
:ok = BotState.set_firmware_version(version)
case String.split(version, ".") do
# Ramps
[_, _, _, "R"] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("arduino")
[_, _, _, "R", _] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("arduino")
# Farmduino
[_, _, _, "F"] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("farmduino")
[_, _, _, "F", _] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("farmduino")
# Farmduino V14
[_, _, _, "G"] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("farmduino_k14")
[_, _, _, "G", _] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("farmduino_k14")
# Farmduino V15
[_, _, _, "H"] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("farmduino_k15")
[_, _, _, "H", _] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("farmduino_k15")
# Express V10
[_, _, _, "E"] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("express_k10")
[_, _, _, "E", _] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("express_k10")
[_, _, _, "S"] ->
_ = Leds.red(:slow_blink)
:ok = BotState.set_firmware_version("none")
:ok = BotState.set_firmware_hardware("none")
[_, _, _, "S", _] ->
_ = Leds.red(:slow_blink)
:ok = BotState.set_firmware_version("none")
:ok = BotState.set_firmware_hardware("none")
end
end
@ -159,8 +192,15 @@ defmodule FarmbotCore.FirmwareSideEffects do
@impl FarmbotFirmware.SideEffects
def handle_debug_message([message]) do
fbos_config = Asset.fbos_config()
should_log? = fbos_config.firmware_debug_log || fbos_config.arduino_debug_messages
should_log? && FarmbotCore.Logger.debug(3, "Firmware debug message: " <> message)
should_log? = fbos_config.firmware_debug_log || fbos_config.arduino_debug_messages
should_log? && do_send_debug_message(message)
end
# TODO(Rick): 0 means OK, but firmware debug logs say "error 0". Why?
def do_send_debug_message("error 0"), do: do_send_debug_message("OK")
def do_send_debug_message(message) do
FarmbotCore.Logger.debug(3, "Firmware debug message: " <> message)
end
@impl FarmbotFirmware.SideEffects

View File

@ -3,17 +3,14 @@ defmodule FarmbotCore.FirmwareTTYDetector do
require Logger
alias Circuits.UART
@expected_names Application.get_env(:farmbot_core, __MODULE__)[:expected_names]
@expected_names ||
Mix.raise("""
Please configure `expected_names` for TTYDetector.
config :farmbot_core, FarmbotCore.FirmwareTTYDetector,
expected_names: ["ttyS0", "ttyNotReal"]
""")
@error_retry_ms 5_000
if System.get_env("FARMBOT_TTY") do
@expected_names ["ttyUSB0", "ttyAMA0", "ttyACM0", System.get_env("FARMBOT_TTY")]
else
@expected_names ["ttyUSB0", "ttyAMA0", "ttyACM0"]
end
@doc "Gets the detected TTY"
def tty(server \\ __MODULE__) do
GenServer.call(server, :tty)
@ -53,7 +50,6 @@ defmodule FarmbotCore.FirmwareTTYDetector do
if farmbot_tty?(name) do
{:noreply, name}
else
# Logger.warn("#{name} is not an expected Farmbot Firmware TTY")
{:noreply, state, {:continue, rest}}
end
end

View File

@ -1,7 +1,5 @@
defmodule FarmbotCore.Leds do
@moduledoc "API for controling Farmbot LEDS."
@led_handler Application.get_env(:farmbot_core, __MODULE__)[:gpio_handler]
@led_handler || Mix.raise("You forgot a led handler!")
@valid_status [:off, :solid, :slow_blink, :fast_blink, :really_fast_blink]
@ -15,29 +13,7 @@ defmodule FarmbotCore.Leds do
def white4(status) when status in @valid_status, do: led_handler().white4(status)
def white5(status) when status in @valid_status, do: led_handler().white5(status)
def factory_test(status) do
red(:off)
blue(:off)
green(:off)
yellow(:off)
white1(:off)
white2(:off)
white3(:off)
white4(:off)
white5(:off)
red(status)
blue(status)
green(status)
yellow(status)
white1(status)
white2(status)
white3(status)
white4(status)
white5(status)
end
defp led_handler,
def led_handler,
do: Application.get_env(:farmbot_core, __MODULE__)[:gpio_handler]
def child_spec(opts) do

View File

@ -13,7 +13,8 @@ defmodule FarmbotCore.Leds.StubHandler do
def white5(status), do: do_debug(:white, status)
defp do_debug(color, status) do
msg = [IO.ANSI.reset(), "LED STATUS: ",
unless System.get_env("LOG_SILENCE") do
msg = [IO.ANSI.reset(), "LED STATUS: ",
apply(IO.ANSI, color, []),
status_in(status),
to_string(color),
@ -22,7 +23,8 @@ defmodule FarmbotCore.Leds.StubHandler do
status_out(status),
IO.ANSI.reset()
]
IO.puts(msg)
IO.puts(msg)
end
end
defp status_in(:slow_blink), do: IO.ANSI.blink_slow()

View File

@ -0,0 +1,31 @@
# This module could have existed within FarmbotCore.Logger.
# Pulling this function into a different module facilitates
# mocking of tests.
defmodule FarmbotCore.LogExecutor do
alias FarmbotCore.Log
def execute(%Log{} = log) do
logger_meta = [
application: :farmbot,
function: log.function,
file: log.file,
line: log.line,
module: log.module,
channels: log.meta[:channels] || log.meta["channels"],
verbosity: log.verbosity,
assertion_passed: log.meta[:assertion_passed]
]
level = log.level
logger_level =
if level in [:info, :debug, :warn, :error],
do: level,
else: :info
unless System.get_env("LOG_SILENCE") do
Elixir.Logger.bare_log(logger_level, log, logger_meta)
end
log
end
end

View File

@ -5,6 +5,7 @@ defmodule FarmbotCore.Logger do
alias FarmbotCore.{Log, Logger.Repo}
import Ecto.Query
@log_types [:info, :debug, :busy, :warn, :success, :error, :fun, :assertion]
@doc "Send a debug message to log endpoints"
defmacro debug(verbosity, message, meta \\ []) do
@ -57,23 +58,27 @@ defmodule FarmbotCore.Logger do
def insert_log!(params) do
changeset = Log.changeset(%Log{}, params)
try do
hash = Ecto.Changeset.get_field(changeset, :hash)
case Repo.get_by(Log, hash: hash) do
nil ->
nil ->
Repo.insert!(changeset)
old ->
params =
old ->
params =
params
|> Map.put(:inserted_at, DateTime.utc_now)
|> Map.put(:inserted_at, DateTime.utc_now())
|> Map.put(:duplicates, old.duplicates + 1)
old
|> Log.changeset(params)
|> Repo.update!()
old
|> Log.changeset(params)
|> Repo.update!()
end
catch
kind, err ->
IO.warn("Error inserting log: #{kind} #{inspect(err)}", __STACKTRACE__)
IO.warn("Error inserting log: #{kind} #{inspect(err)}", __STACKTRACE__)
Ecto.Changeset.apply_changes(changeset)
end
end
@ -94,13 +99,16 @@ defmodule FarmbotCore.Logger do
@doc false
def dispatch_log(%Macro.Env{} = env, level, verbosity, message, meta)
when level in [:info, :debug, :busy, :warn, :success, :error, :fun, :assertion] and is_number(verbosity) and
is_binary(message) and is_list(meta) do
when level in @log_types and
is_number(verbosity) and
is_binary(message) and
is_list(meta) do
fun =
case env.function do
{fun, ar} -> "#{fun}/#{ar}"
nil -> "no_function"
end
%{
level: level,
verbosity: verbosity,
@ -116,29 +124,8 @@ defmodule FarmbotCore.Logger do
@doc false
def dispatch_log(params) do
params
|> insert_log!()
|> elixir_log()
end
defp elixir_log(%Log{} = log) do
logger_meta = [
application: :farmbot,
function: log.function,
file: log.file,
line: log.line,
module: log.module,
channels: log.meta[:channels] || log.meta["channels"],
verbosity: log.verbosity,
assertion_passed: log.meta[:assertion_passed]
# TODO Connor - fix time
# time: time
]
level = log.level
logger_level = if level in [:info, :debug, :warn, :error], do: level, else: :info
Elixir.Logger.bare_log(logger_level, log, logger_meta)
log
log = insert_log!(params)
FarmbotCore.LogExecutor.execute(log)
end
@doc "Helper function for deciding if a message should be logged or not."

View File

@ -7,11 +7,13 @@ defmodule FarmbotCore.Logger.Supervisor do
end
def init([]) do
children = [
supervisor(FarmbotCore.Logger.Repo, [])
]
opts = [strategy: :one_for_all]
supervise(children, opts)
supervise(children(), opts)
end
def children do
default = [supervisor(FarmbotCore.Logger.Repo, [])]
config = Application.get_env(:farmbot_ext, __MODULE__) || []
Keyword.get(config, :children, default)
end
end

View File

@ -10,11 +10,16 @@ defmodule FarmbotCore.StorageSupervisor do
end
def init([]) do
children = [
Supervisor.init(children(), [strategy: :one_for_one])
end
def children do
default = [
FarmbotCore.Logger.Supervisor,
FarmbotCore.Config.Supervisor,
FarmbotCore.Asset.Supervisor
]
Supervisor.init(children, [strategy: :one_for_one])
config = Application.get_env(:farmbot_ext, __MODULE__) || []
Keyword.get(config, :children, default)
end
end

View File

@ -1,21 +1,6 @@
defmodule FarmbotCore.TimeUtils do
@moduledoc "Helper functions for working with time."
def format_time(%DateTime{} = dt) do
"#{format_num(dt.month)}/#{format_num(dt.day)}/#{dt.year} " <>
"at #{format_num(dt.hour)}:#{format_num(dt.minute)}"
end
defp format_num(num), do: :io_lib.format('~2..0B', [num]) |> to_string
# returns midnight of today
@spec build_epoch(DateTime.t) :: DateTime.t
def build_epoch(time) do
tz = FarmbotCore.Asset.fbos_config().timezone
n = Timex.Timezone.convert(time, tz)
Timex.shift(n, hours: -n.hour, seconds: -n.second, minutes: -n.minute)
end
@doc """
Compares a datetime with another.
-1 -- the first date comes before the second one

View File

@ -1,9 +1,15 @@
defmodule FarmbotCore.MixProject do
use Mix.Project
@target System.get_env("MIX_TARGET") || "host"
@version Path.join([__DIR__, "..", "VERSION"]) |> File.read!() |> String.trim()
@branch System.cmd("git", ~w"rev-parse --abbrev-ref HEAD") |> elem(0) |> String.trim()
@elixir_version Path.join([__DIR__, "..", "ELIXIR_VERSION"]) |> File.read!() |> String.trim()
@version Path.join([__DIR__, "..", "VERSION"])
|> File.read!()
|> String.trim()
@branch System.cmd("git", ~w"rev-parse --abbrev-ref HEAD")
|> elem(0)
|> String.trim()
@elixir_version Path.join([__DIR__, "..", "ELIXIR_VERSION"])
|> File.read!()
|> String.trim()
defp commit do
System.cmd("git", ~w"rev-parse --verify HEAD") |> elem(0) |> String.trim()
@ -59,7 +65,8 @@ defmodule FarmbotCore.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:farmbot_celery_script, path: "../farmbot_celery_script", env: Mix.env()},
{:farmbot_celery_script,
path: "../farmbot_celery_script", env: Mix.env()},
{:farmbot_firmware, path: "../farmbot_firmware", env: Mix.env()},
{:farmbot_telemetry, path: "../farmbot_telemetry", env: Mix.env()},
{:elixir_make, "~> 0.6", runtime: false},
@ -68,7 +75,9 @@ defmodule FarmbotCore.MixProject do
{:jason, "~> 1.1"},
{:muontrap, "~> 0.5"},
{:excoveralls, "~> 0.10", only: [:test], targets: [:host]},
{:dialyxir, "~> 1.0.0-rc.3", only: [:dev], targets: [:host], runtime: false},
{:mimic, "~> 1.1", only: [:test]},
{:dialyxir, "~> 1.0.0-rc.3",
only: [:dev], targets: [:host], runtime: false},
{:ex_doc, "~> 0.21.2", only: [:dev], targets: [:host], runtime: false}
]
end

View File

@ -24,6 +24,7 @@
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"mimic": {:hex, :mimic, "1.1.3", "3bad83d5271b4faa7bbfef587417a6605cbbc802a353395d446a1e5f46fe7115", [:mix], [], "hexpm"},
"muontrap": {:hex, :muontrap, "0.5.0", "0b885a4095e990000d519441bccb8f037a9c4c35908720e7814a516a606be278", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_uart": {:hex, :nerves_uart, "1.2.0", "195424116b925cd3bf9d666be036c2a80655e6ca0f8d447e277667a60005c50e", [:mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"},

View File

@ -8,13 +8,29 @@ defmodule FarmbotCore.Asset.Repo.Migrations.CreateRegimenInstancesTable do
add(:epoch, :utc_datetime)
add(:next, :utc_datetime)
add(:next_sequence_id, :id)
add(:regimen_id, references("regimens", type: :binary_id, column: :local_id))
add(:farm_event_id, references("farm_events", type: :binary_id, column: :local_id))
add(
:regimen_id,
references("regimens", type: :binary_id, column: :local_id)
)
add(
:farm_event_id,
references("farm_events", type: :binary_id, column: :local_id)
)
add(:monitor, :boolean, default: true)
timestamps(inserted_at: :created_at, type: :utc_datetime)
end
create(unique_index("persistent_regimens", [:local_id, :regimen_id, :farm_event_id]))
create(
unique_index("persistent_regimens", [
:local_id,
:regimen_id,
:farm_event_id
])
)
create(unique_index("persistent_regimens", :started_at))
create(unique_index("persistent_regimens", :epoch))
end

View File

@ -1,12 +1,9 @@
defmodule FarmbotCore.Asset.Repo.Migrations.ForceResyncPoints do
use Ecto.Migration
alias FarmbotCore.Asset.{Repo, Point}
import Ecto.Query, only: [from: 2]
alias FarmbotCore.Asset.Repo
def change do
for %{id: id} = point when is_integer(id) <- Repo.all(Point) do
Repo.delete!(point)
end
Repo.query("TRUNCATE points")
end
end

View File

@ -1,6 +1,5 @@
defmodule FarmbotCore.Asset.Repo.Migrations.ForceResyncDevice do
use Ecto.Migration
alias FarmbotCore.Asset.{Repo, Device}
def change do
execute("UPDATE devices SET updated_at = \"1970-11-07 16:52:31.618000\"")

View File

@ -1,6 +1,5 @@
defmodule FarmbotCore.Asset.Repo.Migrations.ForceResyncDeviceForMountedToolId do
use Ecto.Migration
alias FarmbotCore.Asset.{Repo, Device}
def change do
execute("UPDATE devices SET updated_at = \"1970-11-07 16:52:31.618000\"")

View File

@ -9,6 +9,8 @@ defmodule FarmbotCore.Asset.Repo.Migrations.ResyncFirmwareConfig do
end
# will resync the firmware params
execute("UPDATE firmware_configs SET updated_at = \"1970-11-07 16:52:31.618000\"")
execute(
"UPDATE firmware_configs SET updated_at = \"1970-11-07 16:52:31.618000\""
)
end
end

Some files were not shown because too many files have changed in this diff Show More