Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MySensorsCore.h 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. * The MySensors Arduino library handles the wireless radio link and protocol
  3. * between your home built sensors/actuators and HA controller of choice.
  4. * The sensors forms a self healing radio network with optional repeaters. Each
  5. * repeater and gateway builds a routing tables in EEPROM which keeps track of the
  6. * network topology allowing messages to be routed to nodes.
  7. *
  8. * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
  9. * Copyright (C) 2013-2018 Sensnology AB
  10. * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
  11. *
  12. * Documentation: http://www.mysensors.org
  13. * Support Forum: http://forum.mysensors.org
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * version 2 as published by the Free Software Foundation.
  18. */
  19. /**
  20. * @file MySensorsCore.h
  21. *
  22. * @defgroup MySensorsCoregrp MySensorsCore
  23. * @ingroup internals
  24. * @{
  25. *
  26. * MySensorsCore-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE
  27. * - [!] Exclamation mark is prepended in case of error or warning
  28. * - SYSTEM:
  29. * - <b>MCO</b> messages emitted by MySensorsCore
  30. * - SUB SYSTEMS:
  31. * - MCO:<b>BGN</b> from @ref _begin()
  32. * - MCO:<b>REG</b> from @ref _registerNode()
  33. * - MCO:<b>SND</b> from @ref send()
  34. * - MCO:<b>PIM</b> from @ref _processInternalCoreMessage()
  35. * - MCO:<b>NLK</b> from @ref _nodeLock()
  36. *
  37. * MySensorsCore debug log messages:
  38. *
  39. * |E| SYS | SUB | Message | Comment
  40. * |-|-----|-----|---------------------------------------------|--------------------------------------------------------------------------------------------------
  41. * |!| MCO | BGN | HW ERR | Error HW initialization (e.g. ext. EEPROM)
  42. * | | MCO | BGN | INIT %%s,CP=%%s,REL=%%d,VER=%%s (%%d) | Core initialization, capabilities (CP), release number (REL), library version (VER)
  43. * | | MCO | BGN | BFR | Callback before()
  44. * | | MCO | BGN | STP | Callback setup()
  45. * | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP): 0=not initialised, 1=initialised, NA=not available
  46. * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter)
  47. * |!| MCO | BGN | TSP FAIL | Transport initialization failed
  48. * | | MCO | REG | REQ | Registration request
  49. * | | MCO | REG | NOT NEEDED | No registration needed (i.e. GW)
  50. * |!| MCO | SND | NODE NOT REG | Node is not registered, cannot send message
  51. * | | MCO | PIM | NODE REG=%%d | Registration response received, registration status (REG)
  52. * | | MCO | SLP | MS=%%lu,SMS=%%d,I1=%%d,M1=%%d,I2=%%d,M2=%%d | Sleep node, time (MS), smartSleep (SMS), Int1/M1, Int2/M2
  53. * | | MCO | SLP | WUP=%%d | Node woke-up, reason/IRQ (WUP)
  54. * |!| MCO | SLP | NTL | Sleeping not possible, no time left
  55. * |!| MCO | SLP | FWUPD | Sleeping not possible, FW update ongoing
  56. * |!| MCO | SLP | REP | Sleeping not possible, repeater feature enabled
  57. * |!| MCO | SLP | TNR | Transport not ready, attempt to reconnect until timeout (MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)
  58. * | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET | Node locked during booting, see signing chapter for additional information
  59. * | | MCO | NLK | TSL | Set transport to sleep
  60. *
  61. *
  62. * @brief API declaration for MySensorsCore
  63. */
  64. #ifndef MySensorsCore_h
  65. #define MySensorsCore_h
  66. #include "Version.h" // Auto generated by bot
  67. #include "MyConfig.h"
  68. #include "MyEepromAddresses.h"
  69. #include "MyMessage.h"
  70. #include <stddef.h>
  71. #include <stdarg.h>
  72. #define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch
  73. #define NODE_SENSOR_ID ((uint8_t)255) //!< Node child is always created/presented when a node is started
  74. #define MY_CORE_VERSION ((uint8_t)2) //!< core version
  75. #define MY_CORE_MIN_VERSION ((uint8_t)2) //!< min core version required for compatibility
  76. #define MY_WAKE_UP_BY_TIMER ((int8_t)-1) //!< Sleeping wake up by timer
  77. #define MY_SLEEP_NOT_POSSIBLE ((int8_t)-2) //!< Sleeping not possible
  78. #define INTERRUPT_NOT_DEFINED ((uint8_t)255) //!< _sleep() param: no interrupt defined
  79. #define MODE_NOT_DEFINED ((uint8_t)255) //!< _sleep() param: no mode defined
  80. #define VALUE_NOT_DEFINED ((uint8_t)255) //!< Value not defined
  81. #define FUNCTION_NOT_SUPPORTED ((uint16_t)0) //!< Function not supported
  82. /**
  83. * @brief Controller configuration
  84. *
  85. * This structure stores controller-related configurations
  86. */
  87. typedef struct {
  88. uint8_t isMetric; //!< Flag indicating if metric or imperial measurements are used
  89. } controllerConfig_t;
  90. /**
  91. * @brief Node core configuration
  92. */
  93. typedef struct {
  94. controllerConfig_t controllerConfig; //!< Controller config
  95. // 8 bit
  96. bool nodeRegistered : 1; //!< Flag node registered
  97. bool presentationSent : 1; //!< Flag presentation sent
  98. uint8_t reserved : 6; //!< reserved
  99. } coreConfig_t;
  100. // **** public functions ********
  101. /**
  102. * Return this nodes id.
  103. */
  104. uint8_t getNodeId(void);
  105. /**
  106. * Return the parent node id.
  107. */
  108. uint8_t getParentNodeId(void);
  109. /**
  110. * Sends node information to the gateway.
  111. */
  112. void presentNode(void);
  113. /**
  114. * Each node must present all attached sensors before any values can be handled correctly by the controller.
  115. * It is usually good to present all attached sensors after power-up in setup().
  116. *
  117. * @param sensorId Select a unique sensor id for this sensor. Choose a number between 0-254.
  118. * @param sensorType The sensor type. See sensor typedef in MyMessage.h.
  119. * @param description A textual description of the sensor.
  120. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
  121. * @param description A textual description of the sensor.
  122. * @return true Returns true if message reached the first stop on its way to destination.
  123. */
  124. bool present(const uint8_t sensorId, const uint8_t sensorType, const char *description="",
  125. const bool ack = false);
  126. #if !defined(__linux__)
  127. bool present(const uint8_t childSensorId, const uint8_t sensorType,
  128. const __FlashStringHelper *description,
  129. const bool ack = false);
  130. #endif
  131. /**
  132. * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do.
  133. * @param name String containing a short Sketch name or NULL if not applicable
  134. * @param version String containing a short Sketch version or NULL if not applicable
  135. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
  136. * @return true Returns true if message reached the first stop on its way to destination.
  137. */
  138. bool sendSketchInfo(const char *name, const char *version, const bool ack = false);
  139. #if !defined(__linux__)
  140. bool sendSketchInfo(const __FlashStringHelper *name, const __FlashStringHelper *version,
  141. const bool ack = false);
  142. #endif
  143. /**
  144. * Sends a message to gateway or one of the other nodes in the radio network
  145. * @param msg Message to send
  146. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
  147. * @return true Returns true if message reached the first stop on its way to destination.
  148. */
  149. bool send(MyMessage &msg, const bool ack = false);
  150. /**
  151. * Send this nodes battery level to gateway.
  152. * @param level Level between 0-100(%)
  153. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
  154. * @return true Returns true if message reached the first stop on its way to destination.
  155. */
  156. bool sendBatteryLevel(const uint8_t level, const bool ack = false);
  157. /**
  158. * Send a heartbeat message (I'm alive!) to the gateway/controller.
  159. * The payload will be an incremental 16 bit integer value starting at 1 when sensor is powered on.
  160. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
  161. * @return true Returns true if message reached the first stop on its way to destination.
  162. */
  163. bool sendHeartbeat(const bool ack = false);
  164. /**
  165. * Send this nodes signal strength to gateway.
  166. * @param level Signal strength can be RSSI if the radio provide it, or another kind of calculation
  167. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
  168. * @return true Returns true if message reached the first stop on its way to destination.
  169. */
  170. bool sendSignalStrength(const int16_t level, const bool ack = false);
  171. /**
  172. * Send this nodes TX power level to gateway.
  173. * @param level For instance, can be TX power level in dbm
  174. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
  175. * @return true Returns true if message reached the first stop on its way to destination.
  176. */
  177. bool sendTXPowerLevel(const uint8_t level, const bool ack = false);
  178. /**
  179. * Requests a value from gateway or some other sensor in the radio network.
  180. * Make sure to add callback-method in begin-method to handle request responses.
  181. *
  182. * @param childSensorId The unique child id for the different sensors connected to this Arduino. 0-254.
  183. * @param variableType The variableType to fetch
  184. * @param destination The nodeId of other node in radio network. Default is gateway
  185. * @return true Returns true if message reached the first stop on its way to destination.
  186. */
  187. bool request(const uint8_t childSensorId, const uint8_t variableType,
  188. const uint8_t destination = GATEWAY_ADDRESS);
  189. /**
  190. * Requests time from controller. Answer will be delivered to receiveTime function in sketch.
  191. * @param ack Set this to true if you want destination node to send ack back to this node. Default is not to request any ack.
  192. * @return true Returns true if message reached the first stop on its way to destination.
  193. */
  194. bool requestTime(const bool ack = false);
  195. /**
  196. * Returns the most recent node configuration received from controller
  197. */
  198. controllerConfig_t getControllerConfig(void);
  199. /**
  200. * Save a state (in local EEPROM). Good for actuators to "remember" state between
  201. * power cycles.
  202. *
  203. * You have 256 bytes to play with. Note that there is a limitation on the number
  204. * of writes the EEPROM can handle (~100 000 cycles on ATMega328).
  205. *
  206. * @param pos The position to store value in (0-255)
  207. * @param value to store in position
  208. */
  209. void saveState(const uint8_t pos, const uint8_t value);
  210. /**
  211. * Load a state (from local EEPROM).
  212. *
  213. * @param pos The position to fetch value from (0-255)
  214. * @return Value to store in position
  215. */
  216. uint8_t loadState(const uint8_t pos);
  217. /**
  218. * Wait for a specified amount of time to pass. Keeps process()ing.
  219. * This does not power-down the radio nor the Arduino.
  220. * Because this calls process() in a loop, it is a good way to wait
  221. * in your loop() on a repeater node or sensor that listens to messages.
  222. * @param waitingMS Number of milliseconds to wait.
  223. */
  224. void wait(const uint32_t waitingMS);
  225. /**
  226. * Wait for a specified amount of time to pass or until specified message received. Keeps process()ing.
  227. * This does not power-down the radio nor the Arduino.
  228. * Because this calls process() in a loop, it is a good way to wait
  229. * in your loop() on a repeater node or sensor that listens to messages.
  230. * @param waitingMS Number of milliseconds to wait.
  231. * @param cmd Command of incoming message.
  232. * @param msgtype Message type.
  233. * @return True if specified message received
  234. */
  235. bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgtype);
  236. /**
  237. * Function to allow scheduler to do some work.
  238. * @remark Internally it will call yield, kick the watchdog and update led states.
  239. */
  240. void doYield(void);
  241. /**
  242. * Sleep (PowerDownMode) the MCU and radio. Wake up on timer.
  243. * @param sleepingMS Number of milliseconds to sleep.
  244. * @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep.
  245. * @return @ref MY_WAKE_UP_BY_TIMER if timer woke it up, @ref MY_SLEEP_NOT_POSSIBLE if not possible (e.g. ongoing FW update)
  246. */
  247. int8_t sleep(const uint32_t sleepingMS, const bool smartSleep = false);
  248. /**
  249. * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change.
  250. * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin
  251. * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3
  252. * @param interrupt Interrupt that should trigger the wakeup
  253. * @param mode RISING, FALLING, CHANGE
  254. * @param sleepingMS Number of milliseconds to sleep or 0 to sleep forever
  255. * @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep
  256. * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
  257. */
  258. int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS = 0,
  259. const bool smartSleep = false);
  260. /**
  261. * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts.
  262. * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin
  263. * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3
  264. * @param interrupt1 First interrupt that should trigger the wakeup
  265. * @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE)
  266. * @param interrupt2 Second interrupt that should trigger the wakeup
  267. * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE)
  268. * @param sleepingMS Number of milliseconds to sleep or 0 to sleep forever
  269. * @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep.
  270. * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
  271. */
  272. int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
  273. const uint8_t mode2, const uint32_t sleepingMS = 0, const bool smartSleep = false);
  274. /**
  275. * \deprecated Use sleep(ms, true) instead
  276. * Same as sleep(), send heartbeat and process incoming messages before going to sleep.
  277. * Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms).
  278. * @param sleepingMS Number of milliseconds to sleep.
  279. * @return @ref MY_WAKE_UP_BY_TIMER if timer woke it up, @ref MY_SLEEP_NOT_POSSIBLE if not possible (e.g. ongoing FW update)
  280. */
  281. int8_t smartSleep(const uint32_t sleepingMS);
  282. /**
  283. * \deprecated Use sleep(interrupt, mode, ms, true) instead
  284. * Same as sleep(), send heartbeat and process incoming messages before going to sleep.
  285. * Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms).
  286. * @param interrupt Interrupt that should trigger the wakeup
  287. * @param mode RISING, FALLING, CHANGE
  288. * @param sleepingMS Number of milliseconds to sleep or 0 to sleep forever
  289. * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
  290. */
  291. int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS = 0);
  292. /**
  293. * \deprecated Use sleep(interrupt1, mode1, interrupt2, mode2, ms, true) instead
  294. * Same as sleep(), send heartbeat and process incoming messages before going to sleep.
  295. * Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms).
  296. * @param interrupt1 First interrupt that should trigger the wakeup
  297. * @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE)
  298. * @param interrupt2 Second interrupt that should trigger the wakeup
  299. * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE)
  300. * @param sleepingMS Number of milliseconds to sleep or 0 to sleep forever
  301. * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
  302. */
  303. int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
  304. const uint8_t mode2, const uint32_t sleepingMS = 0);
  305. /**
  306. * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts.
  307. * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin
  308. * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3
  309. * @param sleepingMS Number of milliseconds to sleep or 0 to sleep forever
  310. * @param interrupt1 (optional) First interrupt that should trigger the wakeup
  311. * @param mode1 (optional) Mode for first interrupt (RISING, FALLING, CHANGE)
  312. * @param interrupt2 (optional) Second interrupt that should trigger the wakeup
  313. * @param mode2 (optional) Mode for second interrupt (RISING, FALLING, CHANGE)
  314. * @param smartSleep (optional) Set True if sending heartbeat and process incoming messages before going to sleep.
  315. * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update)
  316. */
  317. int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep = false,
  318. const uint8_t interrupt1 = INTERRUPT_NOT_DEFINED, const uint8_t mode1 = MODE_NOT_DEFINED,
  319. const uint8_t interrupt2 = INTERRUPT_NOT_DEFINED, const uint8_t mode2 = MODE_NOT_DEFINED);
  320. // **** private functions ********
  321. /**
  322. * @defgroup MyLockgrp MyNodeLock
  323. * @ingroup internals
  324. * @brief API declaration for MyNodeLock
  325. * @{
  326. */
  327. /**
  328. * @brief Lock a node and transmit provided message with 30m intervals
  329. *
  330. * This function is called if suspicious activity has exceeded the threshold (see
  331. * @ref MY_NODE_LOCK_COUNTER_MAX). Unlocking with a normal Arduino bootloader require erasing the EEPROM
  332. * while unlocking with a custom bootloader require holding @ref MY_NODE_UNLOCK_PIN low during power on/reset.
  333. *
  334. * @param str The string to transmit.
  335. */
  336. void _nodeLock(const char* str);
  337. /**
  338. * @brief Check node lock status and prevent node execution if locked.
  339. */
  340. void _checkNodeLock(void);
  341. /** @}*/ // Node lock group
  342. /**
  343. * @brief Node initialisation
  344. */
  345. void _begin(void);
  346. /**
  347. * @brief Main framework process
  348. */
  349. void _process(void);
  350. /**
  351. * @brief Processes internal core message
  352. * @return True if no further processing required
  353. */
  354. bool _processInternalCoreMessage(void);
  355. /**
  356. * @brief Puts node to a infinite loop if unrecoverable situation detected
  357. */
  358. void _infiniteLoop(void);
  359. /**
  360. * @brief Handles registration request
  361. */
  362. void _registerNode(void);
  363. /**
  364. * @brief Sends message according to routing table
  365. * @param message
  366. * @return true Returns true if message reached the first stop on its way to destination.
  367. */
  368. bool _sendRoute(MyMessage &message);
  369. /**
  370. * @brief Callback for incoming messages
  371. * @param message
  372. */
  373. void receive(const MyMessage &message) __attribute__((weak));
  374. /**
  375. * @brief Callback for incoming time messages
  376. */
  377. void receiveTime(uint32_t) __attribute__((weak));
  378. /**
  379. * @brief Node presentation
  380. */
  381. void presentation(void) __attribute__((weak));
  382. /**
  383. * @brief Called before node initialises
  384. */
  385. void before(void) __attribute__((weak));
  386. /**
  387. * @brief Called before any hwInitialization is done
  388. */
  389. void preHwInit(void) __attribute__((weak));
  390. /**
  391. * @brief Called after node initialises but before main loop
  392. */
  393. void setup(void) __attribute__((weak));
  394. /**
  395. * @brief Main loop
  396. */
  397. void loop(void) __attribute__((weak));
  398. // Inline function and macros
  399. static inline MyMessage& build(MyMessage &msg, const uint8_t destination, const uint8_t sensor,
  400. const uint8_t command, const uint8_t type, const bool ack = false)
  401. {
  402. msg.sender = getNodeId();
  403. msg.destination = destination;
  404. msg.sensor = sensor;
  405. msg.type = type;
  406. mSetCommand(msg,command);
  407. mSetRequestAck(msg,ack);
  408. mSetAck(msg,false);
  409. return msg;
  410. }
  411. static inline MyMessage& buildGw(MyMessage &msg, const uint8_t type)
  412. {
  413. msg.sender = GATEWAY_ADDRESS;
  414. msg.destination = GATEWAY_ADDRESS;
  415. msg.sensor = NODE_SENSOR_ID;
  416. msg.type = type;
  417. mSetCommand(msg, C_INTERNAL);
  418. mSetRequestAck(msg, false);
  419. mSetAck(msg, false);
  420. return msg;
  421. }
  422. #endif
  423. /** @}*/