diff --git a/devicetypes/konnected-io/konnected-temperature-humidity-sensor-dht.src/konnected-temperature-humidity-sensor-dht.groovy b/devicetypes/konnected-io/konnected-temperature-humidity-sensor-dht.src/konnected-temperature-humidity-sensor-dht.groovy new file mode 100644 index 0000000..2119333 --- /dev/null +++ b/devicetypes/konnected-io/konnected-temperature-humidity-sensor-dht.src/konnected-temperature-humidity-sensor-dht.groovy @@ -0,0 +1,82 @@ +/** + * Konnected Temperature & Humidity Sensor (DHT) + * + * Copyright 2018 Konnected Inc (https://konnected.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License + * for the specific language governing permissions and limitations under the License. + * + */ +metadata { + definition (name: "Konnected Temperature & Humidity Sensor (DHT)", namespace: "konnected-io", author: "konnected.io") { + capability "Temperature Measurement" + capability "Relative Humidity Measurement" + } + + preferences { + input name: "pollInterval", type: "number", title: "Polling Interval (minutes)", + defaultValue: 3, + description: "Frequency of sensor updates" + } + + tiles { + multiAttributeTile(name:"main", type:"thermostat", width:6, height:4) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState "temperature", label:'${currentValue}°F', unit: "°F", backgroundColors: [ + // Celsius Color Range + [value: 0, color: "#153591"], + [value: 7, color: "#1E9CBB"], + [value: 15, color: "#90D2A7"], + [value: 23, color: "#44B621"], + [value: 29, color: "#F1D801"], + [value: 33, color: "#D04E00"], + [value: 36, color: "#BC2323"], + // Fahrenheit Color Range + [value: 40, color: "#153591"], + [value: 44, color: "#1E9CBB"], + [value: 59, color: "#90D2A7"], + [value: 74, color: "#44B621"], + [value: 84, color: "#F1D801"], + [value: 92, color: "#D04E00"], + [value: 96, color: "#BC2323"] + ] + } + tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { + attributeState("humidity", label:'${currentValue}%', unit:"%", defaultState: true) + } + } + main "main" + details "main" + } +} + +def updated() { + parent.updateSettingsOnDevice() +} + +// Update state sent from parent app +def updateStates(states) { + def temperature = new BigDecimal(states.temp) + if (location.getTemperatureScale() == 'F') { + temperature = temperature * 9 / 5 + 32 + } + sendEvent(name: "temperature", value: temperature.setScale(1, BigDecimal.ROUND_HALF_UP), unit: location.getTemperatureScale()) + + def humidity + if (states.humi) { + humidity = new BigDecimal(states.humi) + sendEvent(name: "humidity", value: humidity.setScale(0, BigDecimal.ROUND_HALF_UP), unit: '%') + } + + log.debug "Temperature: $temperature, Humidity: $humidity" +} + +def pollInterval() { + return pollInterval +} \ No newline at end of file diff --git a/firmware/2.2.0/app/include/user_config.h b/firmware/2.2.0/app/include/user_config.h new file mode 100644 index 0000000..5e4ef3f --- /dev/null +++ b/firmware/2.2.0/app/include/user_config.h @@ -0,0 +1,123 @@ +#ifndef __USER_CONFIG_H__ +#define __USER_CONFIG_H__ + +// #define FLASH_512K +// #define FLASH_1M +// #define FLASH_2M +// #define FLASH_4M +// #define FLASH_8M +// #define FLASH_16M +#define FLASH_AUTOSIZE + +// This adds the asserts in LUA. It also adds some useful extras to the +// node module. This is all silent in normal operation and so can be enabled +// without any harm (except for the code size increase and slight slowdown) +//#define DEVELOPMENT_TOOLS + +#ifdef DEVELOPMENT_TOOLS +extern void luaL_assertfail(const char *file, int line, const char *message); +#define lua_assert(x) ((x) ? (void) 0 : luaL_assertfail(__FILE__, __LINE__, #x)) +#endif + +// This enables lots of debug output and changes the serial bit rate. This +// is normally only used by hardcore developers +//#define DEVELOP_VERSION +#ifdef DEVELOP_VERSION +#define NODE_DEBUG +#define COAP_DEBUG +#endif /* DEVELOP_VERSION */ + +#define BIT_RATE_DEFAULT BIT_RATE_115200 + +// This enables automatic baud rate detection at startup +#define BIT_RATE_AUTOBAUD + +#define NODE_ERROR + +#ifdef NODE_DEBUG +#define NODE_DBG dbg_printf +#else +#define NODE_DBG +#endif /* NODE_DEBUG */ + +#ifdef NODE_ERROR +#define NODE_ERR dbg_printf +#else +#define NODE_ERR +#endif /* NODE_ERROR */ + +#define GPIO_INTERRUPT_ENABLE +#define GPIO_INTERRUPT_HOOK_ENABLE +// #define GPIO_SAFE_NO_INTR_ENABLE + +#define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed)) +#define ICACHE_STORE_ATTR __attribute__((aligned(4))) +#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text"))) +#ifdef GPIO_SAFE_NO_INTR_ENABLE +#define NO_INTR_CODE ICACHE_RAM_ATTR __attribute__ ((noinline)) +#else +#define NO_INTR_CODE inline +#endif + +// SSL buffer size used only for espconn-layer secure connections. +// See https://github.com/nodemcu/nodemcu-firmware/issues/1457 for conversation details. +#define SSL_BUFFER_SIZE 6178 + +#define CLIENT_SSL_ENABLE +//#define MD2_ENABLE +#define SHA2_ENABLE + +#define BUILD_SPIFFS +#define SPIFFS_CACHE 1 + +//#define BUILD_FATFS + +// maximum length of a filename +#define FS_OBJ_NAME_LEN 31 + +// maximum number of open files for SPIFFS +#define SPIFFS_MAX_OPEN_FILES 4 + +// Uncomment this next line for fastest startup +// It reduces the format time dramatically +// #define SPIFFS_MAX_FILESYSTEM_SIZE 32768 +// +// You can force the spiffs file system to be at a fixed location +// #define SPIFFS_FIXED_LOCATION 0x100000 +// +// You can force the SPIFFS file system to end on the next !M boundary +// (minus the 16k parameter space). THis is useful for certain OTA scenarios +// #define SPIFFS_SIZE_1M_BOUNDARY + +// #define LUA_NUMBER_INTEGRAL + +#define READLINE_INTERVAL 80 +#define LUA_TASK_PRIO USER_TASK_PRIO_0 +#define LUA_PROCESS_LINE_SIG 2 +#define LUA_OPTIMIZE_DEBUG 2 + +#define ENDUSER_SETUP_AP_SSID "konnected" + +/* + * A valid hostname only contains alphanumeric and hyphen(-) characters, with no hyphens at first or last char + * if WIFI_STA_HOSTNAME not defined: hostname will default to NODE-xxxxxx (xxxxxx being last 3 octets of MAC address) + * if WIFI_STA_HOSTNAME defined: hostname must only contain alphanumeric characters + * if WIFI_STA_HOSTNAME_APPEND_MAC not defined: Hostname MUST be 32 chars or less + * if WIFI_STA_HOSTNAME_APPEND_MAC defined: Hostname MUST be 26 chars or less, since last 3 octets of MAC address will be appended + * if defined hostname is invalid: hostname will default to NODE-xxxxxx (xxxxxx being last 3 octets of MAC address) +*/ +#define WIFI_STA_HOSTNAME "konnected-" +#define WIFI_STA_HOSTNAME_APPEND_MAC + +//#define WIFI_SMART_ENABLE + +#define WIFI_SDK_EVENT_MONITOR_ENABLE +#define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE + +////#define ENABLE_TIMER_SUSPEND +//#define PMSLEEP_ENABLE + + +#define STRBUF_DEFAULT_INCREMENT 32 + +#endif /* __USER_CONFIG_H__ */ diff --git a/firmware/2.2.0/app/include/user_mbedtls.h b/firmware/2.2.0/app/include/user_mbedtls.h new file mode 100644 index 0000000..a269c5d --- /dev/null +++ b/firmware/2.2.0/app/include/user_mbedtls.h @@ -0,0 +1,313 @@ +#include "c_types.h" + +#include "user_config.h" + +#undef MBEDTLS_HAVE_ASM +#undef MBEDTLS_HAVE_SSE2 + +// These are disabled until we have a real, working RTC-based gettimeofday +#undef MBEDTLS_HAVE_TIME +#undef MBEDTLS_HAVE_TIME_DATE + +#define MBEDTLS_PLATFORM_MEMORY +#undef MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +#undef MBEDTLS_PLATFORM_EXIT_ALT +#undef MBEDTLS_PLATFORM_TIME_ALT +#undef MBEDTLS_PLATFORM_FPRINTF_ALT +#undef MBEDTLS_PLATFORM_PRINTF_ALT +#undef MBEDTLS_PLATFORM_SNPRINTF_ALT +#undef MBEDTLS_PLATFORM_NV_SEED_ALT + +#undef MBEDTLS_DEPRECATED_WARNING +#define MBEDTLS_DEPRECATED_REMOVED + +#undef MBEDTLS_TIMING_ALT +#undef MBEDTLS_AES_ALT +#undef MBEDTLS_ARC4_ALT +#undef MBEDTLS_BLOWFISH_ALT +#undef MBEDTLS_CAMELLIA_ALT +#undef MBEDTLS_DES_ALT +#undef MBEDTLS_XTEA_ALT +#undef MBEDTLS_MD2_ALT +#undef MBEDTLS_MD4_ALT +#undef MBEDTLS_MD5_ALT +#undef MBEDTLS_RIPEMD160_ALT +#undef MBEDTLS_SHA1_ALT +#undef MBEDTLS_SHA256_ALT +#undef MBEDTLS_SHA512_ALT + +#undef MBEDTLS_MD2_PROCESS_ALT +#undef MBEDTLS_MD4_PROCESS_ALT +#undef MBEDTLS_MD5_PROCESS_ALT +#undef MBEDTLS_RIPEMD160_PROCESS_ALT +#undef MBEDTLS_SHA1_PROCESS_ALT +#undef MBEDTLS_SHA256_PROCESS_ALT +#undef MBEDTLS_SHA512_PROCESS_ALT + +#undef MBEDTLS_DES_SETKEY_ALT +#undef MBEDTLS_DES_CRYPT_ECB_ALT +#undef MBEDTLS_DES3_CRYPT_ECB_ALT +#undef MBEDTLS_AES_SETKEY_ENC_ALT +#undef MBEDTLS_AES_SETKEY_DEC_ALT +#undef MBEDTLS_AES_ENCRYPT_ALT +#undef MBEDTLS_AES_DECRYPT_ALT + +#undef MBEDTLS_TEST_NULL_ENTROPY +#define MBEDTLS_ENTROPY_HARDWARE_ALT + +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CFB +#define MBEDTLS_CIPHER_MODE_CTR + +#undef MBEDTLS_CIPHER_NULL_CIPHER + +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +#undef MBEDTLS_ENABLE_WEAK_CIPHERSUITES +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED + +#define MBEDTLS_ECP_NIST_OPTIM + +#undef MBEDTLS_ECDSA_DETERMINISTIC + +#undef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +#undef MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + +#define MBEDTLS_PK_PARSE_EC_EXTENDED + +#undef MBEDTLS_ERROR_STRERROR_DUMMY + +#define MBEDTLS_GENPRIME + +#undef MBEDTLS_FS_IO + +#undef MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_ENTROPY_FORCE_SHA256 +#undef MBEDTLS_ENTROPY_NV_SEED + +#undef MBEDTLS_MEMORY_DEBUG +#undef MBEDTLS_MEMORY_BACKTRACE + +#define MBEDTLS_PK_RSA_ALT_SUPPORT +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_PKCS1_V21 + +#undef MBEDTLS_RSA_NO_CRT +#undef MBEDTLS_SELF_TEST + +#define MBEDTLS_SHA256_SMALLER + +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES +#undef MBEDTLS_SSL_DEBUG_ALL + +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define MBEDTLS_SSL_FALLBACK_SCSV + +#undef MBEDTLS_SSL_HW_RECORD_ACCEL + +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING +#define MBEDTLS_SSL_RENEGOTIATION + +#undef MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO +#undef MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +#undef MBEDTLS_SSL_PROTO_SSL3 +#define MBEDTLS_SSL_PROTO_TLS1 +#define MBEDTLS_SSL_PROTO_TLS1_1 +#define MBEDTLS_SSL_PROTO_TLS1_2 +#undef MBEDTLS_SSL_PROTO_DTLS + +#define MBEDTLS_SSL_ALPN +#undef MBEDTLS_SSL_DTLS_ANTI_REPLAY +#undef MBEDTLS_SSL_DTLS_HELLO_VERIFY +#undef MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE +#undef MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#define MBEDTLS_SSL_SESSION_TICKETS +#define MBEDTLS_SSL_EXPORT_KEYS +#define MBEDTLS_SSL_SERVER_NAME_INDICATION +#define MBEDTLS_SSL_TRUNCATED_HMAC + +#undef MBEDTLS_THREADING_ALT +#undef MBEDTLS_THREADING_PTHREAD + +#define MBEDTLS_VERSION_FEATURES + +#undef MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 +#undef MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +#undef MBEDTLS_ZLIB_SUPPORT + +#undef MBEDTLS_AESNI_C +#define MBEDTLS_AES_C +#define MBEDTLS_ARC4_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_BLOWFISH_C +#define MBEDTLS_CAMELLIA_C +#define MBEDTLS_CCM_C +#undef MBEDTLS_CERTS_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CMAC_C +#define MBEDTLS_CTR_DRBG_C +#undef MBEDTLS_DEBUG_C +#define MBEDTLS_DES_C +#define MBEDTLS_DHM_C +#define MBEDTLS_ECDH_C +#undef MBEDTLS_ECDSA_C +#undef MBEDTLS_ECJPAKE_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_ERROR_C +#define MBEDTLS_GCM_C +#undef MBEDTLS_HAVEGE_C +#define MBEDTLS_HMAC_DRBG_C +#define MBEDTLS_MD_C +#undef MBEDTLS_MD2_C +#undef MBEDTLS_MD4_C +#define MBEDTLS_MD5_C +#undef MBEDTLS_MEMORY_BUFFER_ALLOC_C +#define MBEDTLS_NET_C +#define MBEDTLS_OID_C +#undef MBEDTLS_PADLOCK_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PEM_WRITE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C +#define MBEDTLS_PKCS5_C +#undef MBEDTLS_PKCS11_C +#define MBEDTLS_PKCS12_C +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RIPEMD160_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA512_C +#define MBEDTLS_SSL_CACHE_C +#define MBEDTLS_SSL_COOKIE_C +#define MBEDTLS_SSL_TICKET_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C +#undef MBEDTLS_THREADING_C +#undef MBEDTLS_TIMING_C +#define MBEDTLS_VERSION_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_CRL_PARSE_C +#define MBEDTLS_X509_CSR_PARSE_C +#define MBEDTLS_X509_CREATE_C +#define MBEDTLS_X509_CRT_WRITE_C +#define MBEDTLS_X509_CSR_WRITE_C +#define MBEDTLS_XTEA_C + +#define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */ +#define MBEDTLS_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ + +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 1000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 1000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +#define MBEDTLS_ECP_WINDOW_SIZE 2 /**< Maximum window size used */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */ + +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +#define MBEDTLS_PLATFORM_STD_CALLOC pvPortCalloc /**< Default allocator to use, can be undefined */ +#define MBEDTLS_PLATFORM_STD_FREE vPortFree /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +#define MBEDTLS_PLATFORM_PRINTF_MACRO ets_printf /**< Default printf macro to use, can be undefined */ +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO ets_snprintf /**< Default snprintf macro to use, can be undefined */ +#define MBEDTLS_PLATFORM_VSNPRINTF_MACRO ets_vsnprintf /**< Default vsnprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +#if 0 +// dynamic buffer sizing with espconn_secure_set_size() +extern unsigned int max_content_len; +#define MBEDTLS_SSL_MAX_CONTENT_LEN max_content_len; +#else +// the current mbedtls integration doesn't allow to set the buffer size dynamically: +// MBEDTLS_SSL_MAX_FRAGMENT_LENGTH feature and dynamic sizing are mutually exclusive +// due to non-constant initializer element in app/mbedtls/library/ssl_tls.c:150 +// the buffer size is hardcoded here and value is taken from SSL_BUFFER_SIZE (user_config.h) +#define MBEDTLS_SSL_MAX_CONTENT_LEN SSL_BUFFER_SIZE /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +#endif + +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 +#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 3 /**< Maximum number of intermediate CAs in a verification chain. */ +//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */ diff --git a/firmware/2.2.0/app/include/user_modules.h b/firmware/2.2.0/app/include/user_modules.h new file mode 100644 index 0000000..d580270 --- /dev/null +++ b/firmware/2.2.0/app/include/user_modules.h @@ -0,0 +1,90 @@ +#ifndef __USER_MODULES_H__ +#define __USER_MODULES_H__ + +#define LUA_USE_BUILTIN_STRING // for string.xxx() +#define LUA_USE_BUILTIN_TABLE // for table.xxx() +#define LUA_USE_BUILTIN_COROUTINE // for coroutine.xxx() +#define LUA_USE_BUILTIN_MATH // for math.xxx(), partially work +// #define LUA_USE_BUILTIN_IO // for io.xxx(), partially work + +// #define LUA_USE_BUILTIN_OS // for os.xxx(), not work +// #define LUA_USE_BUILTIN_DEBUG +#define LUA_USE_BUILTIN_DEBUG_MINIMAL // for debug.getregistry() and debug.traceback() + +#ifndef LUA_CROSS_COMPILER + +// The default configuration is designed to run on all ESP modules including the 512 KB modules like ESP-01 and only +// includes general purpose interface modules which require at most two GPIO pins. +// See https://github.com/nodemcu/nodemcu-firmware/pull/1127 for discussions. +// New modules should be disabled by default and added in alphabetical order. +//#define LUA_USE_MODULES_ADC +//#define LUA_USE_MODULES_ADS1115 +//#define LUA_USE_MODULES_ADXL345 +//#define LUA_USE_MODULES_AM2320 +//#define LUA_USE_MODULES_APA102 +#define LUA_USE_MODULES_BIT +//#define LUA_USE_MODULES_BLOOM +//#define LUA_USE_MODULES_BMP085 +//#define LUA_USE_MODULES_BME280 +//#define LUA_USE_MODULES_BME680 +//#define LUA_USE_MODULES_COAP +//#define LUA_USE_MODULES_COLOR_UTILS +//#define LUA_USE_MODULES_CRON +#define LUA_USE_MODULES_CRYPTO +#define LUA_USE_MODULES_DHT +//#define LUA_USE_MODULES_DS18B20 +//#define LUA_USE_MODULES_ENCODER +#define LUA_USE_MODULES_ENDUSER_SETUP // USE_DNS in dhcpserver.h needs to be enabled for this module to work. +#define LUA_USE_MODULES_FILE +//#define LUA_USE_MODULES_GDBSTUB +#define LUA_USE_MODULES_GPIO +//#define LUA_USE_MODULES_GPIO_PULSE +//#define LUA_USE_MODULES_HDC1080 +//#define LUA_USE_MODULES_HMC5883L +#define LUA_USE_MODULES_HTTP +//#define LUA_USE_MODULES_HX711 +#define LUA_USE_MODULES_I2C +//#define LUA_USE_MODULES_L3G4200D +//#define LUA_USE_MODULES_MCP4725 +//#define LUA_USE_MODULES_MDNS +//#define LUA_USE_MODULES_MQTT +#define LUA_USE_MODULES_NET +#define LUA_USE_MODULES_NODE +#define LUA_USE_MODULES_OW +//#define LUA_USE_MODULES_PCM +//#define LUA_USE_MODULES_PERF +//#define LUA_USE_MODULES_PWM +//#define LUA_USE_MODULES_RC +//#define LUA_USE_MODULES_RFSWITCH +//#define LUA_USE_MODULES_ROTARY +//#define LUA_USE_MODULES_RTCFIFO +//#define LUA_USE_MODULES_RTCMEM +//#define LUA_USE_MODULES_RTCTIME +//#define LUA_USE_MODULES_SI7021 +//#define LUA_USE_MODULES_SIGMA_DELTA +#define LUA_USE_MODULES_SJSON +//#define LUA_USE_MODULES_SNTP +//#define LUA_USE_MODULES_SOMFY +//#define LUA_USE_MODULES_SPI +//#define LUA_USE_MODULES_SQLITE3 +//#define LUA_USE_MODULES_STRUCT +//#define LUA_USE_MODULES_SWITEC +// #define LUA_USE_MODULES_TCS34725 +//#define LUA_USE_MODULES_TM1829 +#define LUA_USE_MODULES_TLS +#define LUA_USE_MODULES_TMR +//#define LUA_USE_MODULES_TSL2561 +//#define LUA_USE_MODULES_U8G +#define LUA_USE_MODULES_UART +//#define LUA_USE_MODULES_UCG +//#define LUA_USE_MODULES_WEBSOCKET +#define LUA_USE_MODULES_WIFI +//#define LUA_USE_MODULES_WIFI_MONITOR +//#define LUA_USE_MODULES_WPS +//#define LUA_USE_MODULES_WS2801 +//#define LUA_USE_MODULES_WS2812 +//#define LUA_USE_MODULES_WS2812_EFFECTS +//#define LUA_USE_MODULES_XPT2046 + +#endif /* LUA_CROSS_COMPILER */ +#endif /* __USER_MODULES_H__ */ diff --git a/firmware/2.2.0/app/include/user_version.h b/firmware/2.2.0/app/include/user_version.h new file mode 100644 index 0000000..f64c212 --- /dev/null +++ b/firmware/2.2.0/app/include/user_version.h @@ -0,0 +1,22 @@ +#ifndef __USER_VERSION_H__ +#define __USER_VERSION_H__ + +#include "version.h" /* ESP firmware header */ + +#define NODE_VERSION_MAJOR ESP_SDK_VERSION_MAJOR +#define NODE_VERSION_MINOR ESP_SDK_VERSION_MINOR +#define NODE_VERSION_REVISION ESP_SDK_VERSION_PATCH +#define NODE_VERSION_INTERNAL 0 + +#define NODE_VERSION_STR(x) #x +#define NODE_VERSION_XSTR(x) NODE_VERSION_STR(x) + +#define NODE_VERSION "Konnected firmware 2.2\r\nNodeMCU " ESP_SDK_VERSION_STRING "." NODE_VERSION_XSTR(NODE_VERSION_INTERNAL) + +#ifndef BUILD_DATE +#define BUILD_DATE "20180405" +#endif + +extern char SDK_VERSION[]; + +#endif /* __USER_VERSION_H__ */ diff --git a/firmware/konnected-filesystem-2-1-4-0x80000-32mb.bin b/firmware/konnected-filesystem-0xa0000-32mb.bin similarity index 94% rename from firmware/konnected-filesystem-2-1-4-0x80000-32mb.bin rename to firmware/konnected-filesystem-0xa0000-32mb.bin index e329db2..ea085c2 100644 Binary files a/firmware/konnected-filesystem-2-1-4-0x80000-32mb.bin and b/firmware/konnected-filesystem-0xa0000-32mb.bin differ diff --git a/firmware/konnected-firmware-2-0-5.bin b/firmware/konnected-firmware-2-0-5.bin deleted file mode 100644 index 5f7bcc6..0000000 Binary files a/firmware/konnected-firmware-2-0-5.bin and /dev/null differ diff --git a/firmware/konnected-firmware-2-2-0.bin b/firmware/konnected-firmware-2-2-0.bin new file mode 100644 index 0000000..8b4c4c1 Binary files /dev/null and b/firmware/konnected-firmware-2-2-0.bin differ diff --git a/scripts/build-firmware b/scripts/build-firmware index e091da9..1b93ced 100755 --- a/scripts/build-firmware +++ b/scripts/build-firmware @@ -1,13 +1,14 @@ #!/bin/bash FIRMWARE_PATH=${PWD}/../nodemcu-firmware -IMAGE_NAME=konnected-firmware-2-0-5 +IMAGE_NAME=konnected-firmware-2-2-0 -cp firmware/1.5.4.1/app/include/* $FIRMWARE_PATH/app/include/ +cp firmware/2.2.0/app/include/* $FIRMWARE_PATH/app/include/ cp src/* $FIRMWARE_PATH/local/fs docker run -e "INTEGER_ONLY=1" \ -e "IMAGE_NAME=${IMAGE_NAME}" \ --rm -ti -v $FIRMWARE_PATH:/opt/nodemcu-firmware marcelstoer/nodemcu-build -cp ${FIRMWARE_PATH}/bin/nodemcu_integer_${IMAGE_NAME}.bin firmware/${IMAGE_NAME}.bin \ No newline at end of file +cp ${FIRMWARE_PATH}/bin/nodemcu_integer_${IMAGE_NAME}.bin firmware/${IMAGE_NAME}.bin +cp ${FIRMWARE_PATH}/bin/*-32mb.bin firmware/ \ No newline at end of file diff --git a/scripts/flash b/scripts/flash index d431834..b061c9e 100755 --- a/scripts/flash +++ b/scripts/flash @@ -1,10 +1,10 @@ #!/bin/bash -FIRMWARE_NAME=konnected-firmware-2-0-5 -FILESYSTEM_NAME=konnected-filesystem-2-1-4-0x80000-32mb +FIRMWARE_NAME=konnected-firmware-2-2-0 +FILESYSTEM_NAME=konnected-filesystem-0xa0000-32mb PORT=/dev/cu.wchusbserial1410 esptool.py --port=${PORT} write_flash --flash_mode dio 0x00000 firmware/${FIRMWARE_NAME}.bin -esptool.py --port=${PORT} write_flash --flash_mode dio 0x80000 firmware/${FILESYSTEM_NAME}.bin +esptool.py --port=${PORT} write_flash --flash_mode dio 0xa0000 firmware/${FILESYSTEM_NAME}.bin -tput bel +tput bel \ No newline at end of file diff --git a/smartapps/konnected-io/konnected-connect.src/konnected-connect.groovy b/smartapps/konnected-io/konnected-connect.src/konnected-connect.groovy index 6ba0d72..f6ecb0a 100644 --- a/smartapps/konnected-io/konnected-connect.src/konnected-connect.groovy +++ b/smartapps/konnected-io/konnected-connect.src/konnected-connect.groovy @@ -66,7 +66,11 @@ void registerKnownDevice(mac) { if (state.knownDevices == null) { state.knownDevices = [].toSet() } - state.knownDevices.add(mac) + + if (isNewDevice(mac)) { + log.debug "Registering Konnected device ${mac}" + state.knownDevices.add(mac) + } } void removeKnownDevice(mac) { diff --git a/smartapps/konnected-io/konnected-service-manager.src/konnected-service-manager.groovy b/smartapps/konnected-io/konnected-service-manager.src/konnected-service-manager.groovy index 54ae475..ec1602b 100644 --- a/smartapps/konnected-io/konnected-service-manager.src/konnected-service-manager.groovy +++ b/smartapps/konnected-io/konnected-service-manager.src/konnected-service-manager.groovy @@ -1,7 +1,7 @@ /** * Konnected * - * Copyright 2017 konnected.io + * Copyright 2018 konnected.io * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at: @@ -28,6 +28,7 @@ definition( mappings { path("/device/:mac/:id/:deviceState") { action: [ PUT: "childDeviceStateUpdate"] } + path("/device/:mac") { action: [ PUT: "childDeviceStateUpdate"] } path("/ping") { action: [ GET: "devicePing"] } } @@ -59,7 +60,8 @@ def uninstalled() { token : "", apiUrl : "", sensors : [], - actuators : [] + actuators : [], + dht_sensors: [] ] if (device) { @@ -228,6 +230,7 @@ private pageAssignPins() { private Map pageConfigurationGetDeviceType(Integer i) { def deviceTypes = [:] def sensorPins = [1,2,5,6,7,9] + def digitalSensorPins = [1,2,3,5,6,7,9] def actuatorPins = [1,2,5,6,7,8] if (sensorPins.contains(i)) { @@ -238,6 +241,10 @@ private Map pageConfigurationGetDeviceType(Integer i) { deviceTypes << actuatorsMap() } + if (digitalSensorPins.contains(i)) { + deviceTypes << digitalSensorsMap() + } + return deviceTypes } @@ -338,11 +345,18 @@ def childDeviceConfiguration() { // Child Devices : update state of child device sent from nodemcu def childDeviceStateUpdate() { - def deviceId = params.mac.toUpperCase() + "|" + params.id - log.debug "Received sensor update from Konnected device: $deviceId = $params.deviceState" + def pin = params.id ?: request.JSON.pin + def deviceId = params.mac.toUpperCase() + "|" + pin def device = getChildDevice(deviceId) if (device) { - device.setStatus(params.deviceState) + if (request.JSON?.temp) { + log.debug "Temp: $request.JSON" + device.updateStates(request.JSON) + } else { + def newState = params.deviceState ?: request.JSON.state.toString() + log.debug "Received sensor update from Konnected device: $deviceId = $newState" + device.setStatus(newState) + } } else { log.warn "Device $deviceId not found!" } @@ -360,13 +374,15 @@ def updateSettingsOnDevice() { def device = state.device def sensors = [] def actuators = [] + def dht_sensors = [] def ip = getDeviceIpAndPort(device) def mac = device.mac getAllChildDevices().each { def pin = it.deviceNetworkId.split("\\|")[1] - - if (sensorsMap()[it.name]) { + if (it.name.contains("DHT")) { + dht_sensors = dht_sensors + [ pin : pin, poll_interval : it.pollInterval() ] + } else if (sensorsMap()[it.name]) { sensors = sensors + [ pin : pin ] } else { actuators = actuators + [ pin : pin, trigger : it.triggerLevel() ] @@ -380,7 +396,8 @@ def updateSettingsOnDevice() { token : state.accessToken, apiUrl : apiServerUrl + "/api/smartapps/installations/" + app.id, sensors : sensors, - actuators : actuators + actuators : actuators, + dht_sensors : dht_sensors ] log.debug "Updating settings on device $mac at $ip" @@ -430,6 +447,7 @@ private Map pinMapping() { return [ 1: "Pin D1", 2: "Pin D2", + 3: "Pin D3", 5: "Pin D5", 6: "Pin D6", 7: "Pin D7", @@ -459,5 +477,11 @@ private Map sensorsMap() { ] } +private Map digitalSensorsMap() { + return [ + "Konnected Temperature & Humidity Sensor (DHT)" : "Temperature & Humidity Sensor" + ] +} + private Integer convertHexToInt(hex) { Integer.parseInt(hex,16) } private String convertHexToIP(hex) { [convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".") } \ No newline at end of file diff --git a/spec/server_device_spec.lua b/spec/server_device_spec.lua index 0fabcf3..04b7041 100644 --- a/spec/server_device_spec.lua +++ b/spec/server_device_spec.lua @@ -2,7 +2,7 @@ describe("server_device", function() local server, response setup(function() - _G.cjson = require("cjson") + _G.sjson = require("sjson") _G.blinktimer = mock({ start = function() end }) server = require("server_device") require("spec/nodemcu_stubs") @@ -31,7 +31,7 @@ describe("server_device", function() end) it("responds with the new pin state", function() - assert.stub(response.send).was.called_with(cjson.encode({ pin = 1, state = 1 })) + assert.stub(response.send).was.called_with(sjson.encode({ pin = 1, state = 1 })) end) end) @@ -58,7 +58,7 @@ describe("server_device", function() end) it("responds with the new pin state", function() - assert.stub(response.send).was.called_with(cjson.encode({ pin = 1, state = 0 })) + assert.stub(response.send).was.called_with(sjson.encode({ pin = 1, state = 0 })) end) end) end) diff --git a/src/application.lua b/src/application.lua index 758d600..f311225 100644 --- a/src/application.lua +++ b/src/application.lua @@ -1,4 +1,5 @@ local sensors = require("sensors") +local dht_sensors = require("dht_sensors") local actuators = require("actuators") local smartthings = require("smartthings") local sensorSend = {} @@ -24,11 +25,32 @@ for i, actuator in pairs(actuators) do gpio.write(actuator.pin, actuator.trigger == gpio.LOW and gpio.HIGH or gpio.LOW) end +if #dht_sensors > 0 then + require("dht") + + local function readDht(pin) + local status, temp, humi, temp_dec, humi_dec = dht.read(pin) + if status == dht.OK then + local temperature_string = temp .. "." .. temp_dec + local humidity_string = humi .. "." .. humi_dec + print("Heap:", node.heap(), "Temperature:", temperature_string, "Humidity:", humidity_string) + table.insert(sensorSend, { pin = pin, temp = temperature_string, humi = humidity_string }) + end + end + + for i, sensor in pairs(dht_sensors) do + local pollInterval = (sensor.poll_interval or 3) * 60 * 1000 + print("Heap:", node.heap(), "Polling pin " .. sensor.pin .. " every " .. pollInterval .. "ms") + tmr.create():alarm(pollInterval, tmr.ALARM_AUTO, function() readDht(sensor.pin) end) + readDht(sensor.pin) + end +end + sensorTimer:alarm(200, tmr.ALARM_AUTO, function(t) for i, sensor in pairs(sensors) do if sensor.state ~= gpio.read(sensor.pin) then sensor.state = gpio.read(sensor.pin) - table.insert(sensorSend, i) + table.insert(sensorSend, {pin = sensor.pin, state = sensor.state}) end end end) @@ -36,15 +58,20 @@ end) sendTimer:alarm(200, tmr.ALARM_AUTO, function(t) if sensorSend[1] then t:stop() - local sensor = sensors[sensorSend[1]] + local sensor = sensorSend[1] timeout:start() http.put( - table.concat({ smartthings.apiUrl, "/device/", dni, "/", sensor.pin, "/", gpio.read(sensor.pin) }), - table.concat({ "Authorization: Bearer ", smartthings.token, "\r\n" }), - "", + table.concat({ smartthings.apiUrl, "/device/", dni}), + table.concat({ "Authorization: Bearer ", smartthings.token, "\r\nAccept: application/json\r\nContent-Type: application/json\r\n" }), + sjson.encode(sensor), function(code) timeout:stop() - print("Heap:", node.heap(), "HTTP Call:", code, "Pin:", sensor.pin, "State:", gpio.read(sensor.pin)) + local a = {"Heap:", node.heap(), "HTTP Call:", code } + for k, v in pairs(sensor) do + table.insert(a, k) + table.insert(a, v) + end + print(unpack(a)) table.remove(sensorSend, 1) blinktimer:start() t:start() diff --git a/src/device.lua b/src/device.lua index 2ec8bd9..11cf2f4 100644 --- a/src/device.lua +++ b/src/device.lua @@ -1,8 +1,8 @@ local me = { id = "uuid:8f655392-a778-4fee-97b9-4825918" .. string.format("%x", node.chipid()), name = "Konnected", - hwVersion = "2.0.5", - swVersion = "2.1.4", + hwVersion = "2.2.0", + swVersion = "2.2.0", http_port = math.floor(node.chipid()/1000) + 8000, urn = "urn:schemas-konnected-io:device:Security:1" } diff --git a/src/dht_sensors.lua b/src/dht_sensors.lua new file mode 100644 index 0000000..0e931a0 --- /dev/null +++ b/src/dht_sensors.lua @@ -0,0 +1,2 @@ +local dht_sensors = {} +return dht_sensors \ No newline at end of file diff --git a/src/http_index.html.gz b/src/http_index.html.gz index fd636bc..0c0eaf8 100644 Binary files a/src/http_index.html.gz and b/src/http_index.html.gz differ diff --git a/src/httpd_req.lua b/src/httpd_req.lua index 8005367..36ebc0d 100644 --- a/src/httpd_req.lua +++ b/src/httpd_req.lua @@ -1,3 +1,5 @@ +local module = ... + local httpdRequestHandler = { method = nil, query = { }, @@ -5,30 +7,33 @@ local httpdRequestHandler = { contentType = nil, body = nil } -local httpdRequest = { - new = function (data) - local _, _, method, path, query = string.find(data, '([A-Z]+) (.+)?(.+) HTTP') - if method == nil then - _, _, method, path = string.find(data, '([A-Z]+) (.+) HTTP') - end - - if query ~= nil then - query = string.gsub(query, '%%(%x%x)', function(x) string.char(tonumber(x, 16)) end) - for k, v in string.gmatch(query, '([^&]+)=([^&]*)&*') do - httpdRequestHandler.query[k] = v - end - end - - httpdRequestHandler.method = method - httpdRequestHandler.path = path - httpdRequestHandler.contentType = string.match(data, "Content%-Type: ([%w/-]+)") - httpdRequestHandler.body = string.sub(data, string.find(data, "\r\n\r\n", 1, true), #data) - - if httpdRequestHandler.contentType == "application/json" then - httpdRequestHandler.body = cjson.decode(httpdRequestHandler.body) +local function httpdRequest(data) + local _, _, method, path, query = string.find(data, '([A-Z]+) (.+)?(.+) HTTP') + if method == nil then + _, _, method, path = string.find(data, '([A-Z]+) (.+) HTTP') + end + + if query ~= nil then + query = string.gsub(query, '%%(%x%x)', function(x) string.char(tonumber(x, 16)) end) + for k, v in string.gmatch(query, '([^&]+)=([^&]*)&*') do + httpdRequestHandler.query[k] = v end - - return httpdRequestHandler end -} -return httpdRequest \ No newline at end of file + + httpdRequestHandler.method = method + httpdRequestHandler.path = path + httpdRequestHandler.contentType = string.match(data, "Content%-Type: ([%w/-]+)") + httpdRequestHandler.body = string.sub(data, string.find(data, "\r\n\r\n", 1, true), #data) + + if httpdRequestHandler.contentType == "application/json" then + httpdRequestHandler.body = sjson.decode(httpdRequestHandler.body) + end + + return httpdRequestHandler +end + +return function(data) + package.loaded[module] = nil + module = nil + return httpdRequest(data) +end \ No newline at end of file diff --git a/src/httpd_res.lua b/src/httpd_res.lua index 7226f19..6c44401 100644 --- a/src/httpd_res.lua +++ b/src/httpd_res.lua @@ -1,14 +1,13 @@ -local httpdResponse -local httpdResponseHandler -local sck = nil +local module = ... -local send = function (body, ty, st) +local function respondWithText(sck, body, ty, st) local ty = ty or "application/json" local st = st or 200 local sendContent = table.concat({'HTTP/1.1 ', st, '\r\nContent-Type: ', ty, '\r\nContent-Length: ', string.len(body), '\r\n\r\n', body}) local function doSend(s) if sendContent == '' then s:close() + sendContent = nil else s:send(string.sub(sendContent, 1, 512)) sendContent = string.sub(sendContent, 513) @@ -18,7 +17,8 @@ local send = function (body, ty, st) sck:on('sent', doSend) doSend(sck) end -local file = function (filename, ty, st) + +local function respondWithFile(sck, filename, ty, st) local ty = ty or "text/html" local st = st or 200 if file.exists(filename .. '.gz') then @@ -27,7 +27,7 @@ local file = function (filename, ty, st) send("", ty, 404) return end - + local header = {'HTTP/1.1 ', st, '\r\nContent-Type: ', ty, '\r\n'} if string.sub(filename, -3) == '.gz' then table.insert(header, 'Content-Encoding: gzip\r\n') @@ -35,7 +35,7 @@ local file = function (filename, ty, st) table.insert(header, '\r\n') header = table.concat(header) local i = 0 - sck:on('sent', function(s) + local function doSend(s) local f = file.open(filename, 'r') if f.seek('set', i) then local buf = file.read(512) @@ -45,17 +45,17 @@ local file = function (filename, ty, st) s:close() end f.close() - end) + end + sck:on('sent', doSend) sck:send(header) end -httpdResponseHandler = { - send = send, - file = file -} -httpdResponse = { - new = function (s) - sck = s - return httpdResponseHandler - end + +local httpdResponse = { + text = respondWithText, + file = respondWithFile } -return httpdResponse \ No newline at end of file + +return function() + package.loaded[module] = nil + return httpdResponse +end \ No newline at end of file diff --git a/src/manifest.json b/src/manifest.json index 0ac0872..b5ae221 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,27 +1,30 @@ { "src/actuators.lua":"47a1a50c0c8cfb547554ded22a8134eaed76c0a3", - "src/application.lua":"758d600770046868d054b7d54bf2144a9fc255e1", - "src/device.lua":"2ec8bd9215cc75c4fc02909e1075806a5bf56413", + "src/application.lua":"f3112252f3548b49b16d0b8a8ae9cdc63da51a3a", + "src/device.lua":"11cf2f4d39cc86c2f19f071b4ec17d2f8b9be76f", + "src/dht_sensors.lua":"0e931a0fea562883140a7f6f33ce8238424d263a", "src/enduser_setup.html.gz":"fbf730b33c309ceab15e88f162f43c232593f7da", "src/http_favicon.ico.gz":"483f371c590b0407c380d019bcc6938cf1d62f0a", - "src/http_index.html.gz":"fd636bc1a6080c94949c77953598964493aec2b0", - "src/httpd_req.lua":"80053674f20f087e58e1cfd490fc71e6cdd92acf", - "src/httpd_res.lua":"7226f19699168e171970cda73b953a49450b7aa8", + "src/http_index.html.gz":"0c0eaf8e051881d58484ab872e51a5a81f47c08d", + "src/httpd_req.lua":"36ebc0d4fc8344f286ffa89deedde8e50d6aa718", + "src/httpd_res.lua":"6c44401701ba0eafeb6f2cf175dff587cdb8105f", "src/init.lua":"6f145587fef8616a5446a1e3f953789a0470278f", "src/led_flip.lua":"590e7be1afe686f4213d097d0e9dba9e7a3910a0", - "src/manifest.json":"9a74353636bdfc06dc68d96e62e3804f9fe0b159", + "src/manifest.json":"18fab37d2bb2c7270c816992e242292f51a8033a", "src/sensors.lua":"d0d94fa73f713dcf2c517da9262f59f306b81d2b", - "src/server.lua":"dcd67fa56836f63472efe1bfd695e47fd70737b1", - "src/server_device.lua":"e42129a0bd32e55c3c2ba3b4db310143837aa645", - "src/server_settings.lua":"6c77ab7a31be9c87ec654bca79091fbd9720748b", - "src/server_status.lua":"eb099e23239f57363683e8661266934eff3e0503", + "src/server.lua":"1649e94819773d6920b9e96d3ca5966c2a589189", + "src/server_device.lua":"484441af8781b9b5a63f8807a14addda27ed5e99", + "src/server_receiver.lua":"82d59d15042a181606a7437de9e919721f834f36", + "src/server_settings.lua":"adecc037cc4ae320e9bb47e147eafba9d4e3db70", + "src/server_status.lua":"e1dfab934475fef8fd16f51592f0a0ee3b632a14", "src/smartthings.lua":"ae11130360416aec5c2505c06850c5a4cd0449da", - "src/ssdp.lua":"f2776ae2c333093e3d954950f13d77b3d880aee1", + "src/ssdp.lua":"fb2088e9088f65757a7bec6304f688178b5e1cbe", + "src/ssdp_response.lua":"9ff33e6dc7a6a190e19f9b2735146c9816db44c2", "src/start.lua":"af90c766d9afa65c6cbcddacb7ab91124b3598c6", - "src/update.lua":"3d2f52af3873583b08e387759b9e32b4f659c357", - "src/update_manifest.lua":"51d4e6c1cd1f9332ecf315a9c104f2cf866e7620", + "src/update.lua":"5ac32ba8b3222399f1cddedd9584b6e72ff236dd", + "src/update_manifest.lua":"e3697f4f6ccd796771ec0de7f17709ad501cf2ae", "src/update_process.lua":"b6ac63039a0edf5e816bcd17b44704f9deb6000d", - "src/variables_build.lua":"fce4b2ce56bef0f50b09e0341cdf5eb7b9be0241", - "src/variables_set.lua":"2c2d9c13c8acb577d80f40e4b513c7cd23ffdd1f", - "updated_at":"2018-03-13:01:49:58" + "src/variables_build.lua":"b421b481a4f48ef68e063af0c2901e564d290f6a", + "src/variables_set.lua":"a4f6a93151cbedf0bd5e533bf2ccfec96834edbd", + "updated_at":"2018-05-07:15:06:34" } diff --git a/src/server.lua b/src/server.lua index dcd67fa..1649e94 100644 --- a/src/server.lua +++ b/src/server.lua @@ -2,77 +2,17 @@ local device = require("device") print("Heap: ", node.heap(), "UPnP: ", "Listening for UPnP discovery") net.multicastJoin(wifi.sta.getip(), "239.255.255.250") -local upnp = net.createServer(net.UDP) -upnp:listen(1900, "239.255.255.250") -upnp:on("receive", function(c, d) - if string.match(d, "M-SEARCH") then - local urn = d:match("ST: (urn:[%w%p]*)") - if (urn == device.urn or string.match(d, "ST: ssdp:all")) then - local resp = - "HTTP/1.1 200 OK\r\n" .. - "Cache-Control: max-age=120\r\n" .. - "ST: " .. device.urn .. "\r\n" .. - "USN: " .. device.id .. "::" .. device.urn .. "\r\n" .. "EXT:\r\n" .. - "SERVER: NodeMCU/" .. string.format("%d.%d.%d", node.info()) .. " UPnP/1.1 " .. device.name .. "/" .. device.swVersion .. "\r\n" .. - "LOCATION: http://" .. wifi.sta.getip() .. ":" .. device.http_port .. "/Device.xml\r\n\r\n" - c:send(resp) - print("Heap: ", node.heap(), "Responded to UPnP Discovery request") - resp = nil - end - end +local upnp = net.createUDPSocket() +upnp:listen(1900, "0.0.0.0") +upnp:on("receive", function(c, d, port, ip) + require("ssdp_response")(c, d, port, ip) end) - print("Heap: ", node.heap(), "HTTP: ", "Starting server at http://" .. wifi.sta.getip() .. ":" .. device.http_port) local http = net.createServer(net.TCP, 10) http:listen(device.http_port, function(conn) - conn:on("receive", function( sck, payload ) - - -- Some clients send POST data in multiple chunks. - -- Collect data packets until the size of HTTP body meets the Content-Length stated in header - -- this snippet borrowed from https://github.com/marcoskirsch/nodemcu-httpserver/blob/master/httpserver.lua - if payload:find("Content%-Length:") or bBodyMissing then - if fullPayload then fullPayload = fullPayload .. payload else fullPayload = payload end - if (tonumber(string.match(fullPayload, "%d+", fullPayload:find("Content%-Length:")+16)) > #fullPayload:sub(fullPayload:find("\r\n\r\n", 1, true)+4, #fullPayload)) then - bBodyMissing = true - return - else - payload = fullPayload - fullPayload, bBodyMissing = nil - end - end - collectgarbage() - - local request = require("httpd_req").new(payload) - local response = require("httpd_res").new(sck) - - if request.path == "/" then - response.file("http_index.html") - end - - if request.path == "/favicon.ico" then - response.file("http_favicon.ico", "image/x-icon") - end - - if request.path == "/Device.xml" then - response.send(dofile("ssdp.lc"), "text/xml") - print("Heap: ", node.heap(), "HTTP: ", "Discovery") - end - - if request.path == "/settings" then - print("Heap: ", node.heap(), "HTTP: ", "Settings") - require("server_settings").process(request,response) - end - - if request.path == "/device" then - print("Heap: ", node.heap(), "HTTP: ", "Device") - require("server_device").process(request,response) - end - - if request.path == "/status" then - print("Heap: ", node.heap(), "HTTP: ", "Status") - require("server_status").process(request,response) - end + conn:on("receive", function(c, payload) + require("server_receiver")(c, payload) end) end) diff --git a/src/server_device.lua b/src/server_device.lua index e42129a..484441a 100644 --- a/src/server_device.lua +++ b/src/server_device.lua @@ -1,3 +1,5 @@ +local module = ... + local function turnOffIn(pin, on_state, delay, times, pause) local off = on_state == 0 and 1 or 0 times = times or 1 @@ -18,41 +20,44 @@ local function turnOffIn(pin, on_state, delay, times, pause) end) end -local me = { - process = function (request, response) - if request.method == "GET" then - if request.query then - request.query.pin = request.query.pin or "all" - end - local body = {} - if request.query.pin == "all" then - local sensors = require("sensors") - for i, sensor in pairs(sensors) do - table.insert(body, { pin = sensor.pin, state = sensor.state }) - end - else - body = { { - pin = request.query.pin, - state = gpio.read(request.query.pin) - } } +local function process(request) + if request.method == "GET" then + if request.query then + request.query.pin = request.query.pin or "all" + end + local body = {} + if request.query.pin == "all" then + local sensors = require("sensors") + for i, sensor in pairs(sensors) do + table.insert(body, { pin = sensor.pin, state = sensor.state }) end - response.send(cjson.encode(body)) + else + body = { { + pin = request.query.pin, + state = gpio.read(request.query.pin) + } } end + return sjson.encode(body) + end - if request.contentType == "application/json" then - if request.method == "PUT" then - print("Heap:", node.heap(), "Actuator Pin:", request.body.pin, "State:", request.body.state) - gpio.write(request.body.pin, request.body.state) - if request.body.momentary then - turnOffIn(request.body.pin, request.body.state, request.body.momentary, request.body.times, request.body.pause) - local off = on_state == 0 and 1 or 0 - response.send(cjson.encode({ pin = request.body.pin, state = off })) - else - response.send(cjson.encode({ pin = request.body.pin, state = request.body.state })) - end - blinktimer:start() + if request.contentType == "application/json" then + if request.method == "PUT" then + print("Heap:", node.heap(), "Actuator Pin:", request.body.pin, "State:", request.body.state) + gpio.write(request.body.pin, request.body.state) + if request.body.momentary then + turnOffIn(request.body.pin, request.body.state, request.body.momentary, request.body.times, request.body.pause) + local off = on_state == 0 and 1 or 0 + return sjson.encode({ pin = request.body.pin, state = off }) + else + return sjson.encode({ pin = request.body.pin, state = request.body.state }) end + blinktimer:start() end end -} -return me \ No newline at end of file +end + +return function(request) + package.loaded[module] = nil + module = nil + return process(request) +end \ No newline at end of file diff --git a/src/server_receiver.lua b/src/server_receiver.lua new file mode 100644 index 0000000..82d59d1 --- /dev/null +++ b/src/server_receiver.lua @@ -0,0 +1,60 @@ +local module = ... + +local function httpReceiver(sck, payload) + + -- Some clients send POST data in multiple chunks. + -- Collect data packets until the size of HTTP body meets the Content-Length stated in header + -- this snippet borrowed from https://github.com/marcoskirsch/nodemcu-httpserver/blob/master/httpserver.lua + if payload:find("Content%-Length:") or bBodyMissing then + if fullPayload then fullPayload = fullPayload .. payload else fullPayload = payload end + if (tonumber(string.match(fullPayload, "%d+", fullPayload:find("Content%-Length:")+16)) > #fullPayload:sub(fullPayload:find("\r\n\r\n", 1, true)+4, #fullPayload)) then + bBodyMissing = true + return + else + payload = fullPayload + fullPayload, bBodyMissing = nil + end + end + collectgarbage() + + local request = require("httpd_req")(payload) + local response = require("httpd_res")() + + if request.path == "/" then + print("Heap: ", node.heap(), "HTTP: ", "Index") + response.file(sck, "http_index.html") + end + + if request.path == "/favicon.ico" then + response.file(sck, "http_favicon.ico", "image/x-icon") + end + + if request.path == "/Device.xml" then + response.text(sck, require("ssdp")(), "text/xml") + print("Heap: ", node.heap(), "HTTP: ", "Discovery") + end + + if request.path == "/settings" then + print("Heap: ", node.heap(), "HTTP: ", "Settings") + response.text(sck, require("server_settings")(request)) + end + + if request.path == "/device" then + print("Heap: ", node.heap(), "HTTP: ", "Device") + response.text(sck, require("server_device")(request)) + end + + if request.path == "/status" then + print("Heap: ", node.heap(), "HTTP: ", "Status") + response.text(sck, require("server_status")()) + end + + sck, request, response = nil + collectgarbage() +end + +return function(sck, payload) + package.loaded[module] = nil + module = nil + httpReceiver(sck, payload) +end \ No newline at end of file diff --git a/src/server_settings.lua b/src/server_settings.lua index 6c77ab7..adecc03 100644 --- a/src/server_settings.lua +++ b/src/server_settings.lua @@ -1,42 +1,47 @@ +local module = ... local restartTimer = tmr.create() restartTimer:register(2000, tmr.ALARM_SINGLE, function() node.restart() end) -local me = { - process = function (request, response) - if request.method == "GET" then - if request.query then - request.query.update = request.query.update or "false" - request.query.force = request.query.force or "false" - request.query.setfactory = request.query.setfactory or "false" - request.query.restart = request.query.restart or "false" - request.query.restore = request.query.restore or "false" - request.query.commitish = request.query.commitish or "master" - end - if request.query.update == "true" then - require("variables_set").set("update_init", "{ force = "..request.query.force..", setfactory = "..request.query.setfactory..", commitish = \""..request.query.commitish.."\" }") - restartTimer:start() - end - if request.query.restart == "true" then - restartTimer:start() - end - if request.query.restore == "true" then - node.restore() - restartTimer:start() - end - response.send("") - end - if request.contentType == "application/json" then - if request.method == "PUT" then - local var = require("variables_set") - var.set("smartthings", table.concat({ "{ token = \"", request.body.token, "\",\r\n apiUrl = \"", request.body.apiUrl, "\" }" })) - var.set("sensors", require("variables_build").build(request.body.sensors)) - var.set("actuators", require("variables_build").build(request.body.actuators)) +local function process(request) + if request.method == "GET" then + if request.query then + request.query.update = request.query.update or "false" + request.query.force = request.query.force or "false" + request.query.setfactory = request.query.setfactory or "false" + request.query.restart = request.query.restart or "false" + request.query.restore = request.query.restore or "false" + request.query.commitish = request.query.commitish or "master" + end + if request.query.update == "true" then + require("variables_set")("update_init", "{ force = "..request.query.force..", setfactory = "..request.query.setfactory..", commitish = \""..request.query.commitish.."\" }") + restartTimer:start() + end + if request.query.restart == "true" then + restartTimer:start() + end + if request.query.restore == "true" then + node.restore() + restartTimer:start() + end + return "" + end + if request.contentType == "application/json" then + if request.method == "PUT" then + local setVar = require("variables_set") + setVar("smartthings", table.concat({ "{ token = \"", request.body.token, "\",\r\n apiUrl = \"", request.body.apiUrl, "\" }" })) + setVar("sensors", require("variables_build")(request.body.sensors)) + setVar("actuators", require("variables_build")(request.body.actuators)) + setVar("dht_sensors", require("variables_build")(request.body.dht_sensors)) - print('Settings updated! Restarting in 5 seconds...') - restartTimer:start() - - response.send("") - end - end - end -} -return me \ No newline at end of file + print('Settings updated! Restarting in 5 seconds...') + restartTimer:start() + + return "" + end + end +end + +return function(request) + package.loaded[module] = nil + module = nil + return process(request) +end \ No newline at end of file diff --git a/src/server_status.lua b/src/server_status.lua index eb099e2..e1dfab9 100644 --- a/src/server_status.lua +++ b/src/server_status.lua @@ -1,22 +1,27 @@ -local me = { - process = function (request, response) - local ip, nm, gw = wifi.sta.getip() - local device = require("device") - local body = { - hwVersion = device.hwVersion, - swVersion = device.swVersion, - heap = node.heap(), - uptime = tmr.time(), - ip = ip, - port = math.floor(node.chipid()/1000) + 8000, - nm = nm, - gw = gw, - mac = wifi.sta.getmac(), - rssi = wifi.sta.getrssi(), - sensors = require("sensors"), - actuators = require("actuators") - } - response.send(cjson.encode(body)) - end -} -return me +local module = ... + +local function process() + local ip, nm, gw = wifi.sta.getip() + local device = require("device") + local body = { + hwVersion = device.hwVersion, + swVersion = device.swVersion, + heap = node.heap(), + uptime = tmr.time(), + ip = ip, + port = math.floor(node.chipid()/1000) + 8000, + nm = nm, + gw = gw, + mac = wifi.sta.getmac(), + rssi = wifi.sta.getrssi(), + sensors = require("sensors"), + actuators = require("actuators") + } + return sjson.encode(body) +end + +return function() + package.loaded[module] = nil + module = nil + return process() +end \ No newline at end of file diff --git a/src/ssdp.lua b/src/ssdp.lua index f2776ae..fb2088e 100644 --- a/src/ssdp.lua +++ b/src/ssdp.lua @@ -1,16 +1,26 @@ -local device = require("device") -local deviceXML = { "\r\n", "\r\n" } -table.insert(deviceXML, " 10\r\n" ) -table.insert(deviceXML, " http://" .. wifi.sta.getip() .. ":" .. device.http_port .. "\r\n" ) -table.insert(deviceXML, " \r\n " .. device.urn .. "\r\n" ) -table.insert(deviceXML, " " .. device.name .. "\r\n" ) -table.insert(deviceXML, " konnected.io\r\n" ) -table.insert(deviceXML, " http://konnected.io/\r\n" ) -table.insert(deviceXML, " Konnected Security\r\n" ) -table.insert(deviceXML, " " .. device.name .. "\r\n" ) -table.insert(deviceXML, " " .. device.swVersion .. "\r\n" ) -table.insert(deviceXML, " " .. node.chipid() .. "\r\n" ) -table.insert(deviceXML, " " .. device.id .. "\r\n" ) -table.insert(deviceXML, " /\r\n" ) -table.insert(deviceXML, " \r\n\r\n" ) -return table.concat(deviceXML) +local module = ... + +local function discoveryXML() + local device = require("device") + local deviceXML = { "\r\n", "\r\n" } + table.insert(deviceXML, " 10\r\n" ) + table.insert(deviceXML, " http://" .. wifi.sta.getip() .. ":" .. device.http_port .. "\r\n" ) + table.insert(deviceXML, " \r\n " .. device.urn .. "\r\n" ) + table.insert(deviceXML, " " .. device.name .. "\r\n" ) + table.insert(deviceXML, " konnected.io\r\n" ) + table.insert(deviceXML, " http://konnected.io/\r\n" ) + table.insert(deviceXML, " Konnected Security\r\n" ) + table.insert(deviceXML, " " .. device.name .. "\r\n" ) + table.insert(deviceXML, " " .. device.swVersion .. "\r\n" ) + table.insert(deviceXML, " " .. node.chipid() .. "\r\n" ) + table.insert(deviceXML, " " .. device.id .. "\r\n" ) + table.insert(deviceXML, " /\r\n" ) + table.insert(deviceXML, " \r\n\r\n" ) + return table.concat(deviceXML) +end + +return function() + package.loaded[module] = nil + module = nil + return discoveryXML() +end \ No newline at end of file diff --git a/src/ssdp_response.lua b/src/ssdp_response.lua new file mode 100644 index 0000000..9ff33e6 --- /dev/null +++ b/src/ssdp_response.lua @@ -0,0 +1,26 @@ +local module = ... + +local function ssdpResponse(c, d, port, ip) + local device = require("device") + if string.match(d, "M-SEARCH") then + local urn = d:match("ST: (urn:[%w%p]*)") + if (urn == device.urn or string.match(d, "ST: ssdp:all")) then + local resp = + "HTTP/1.1 200 OK\r\n" .. + "Cache-Control: max-age=120\r\n" .. + "ST: " .. device.urn .. "\r\n" .. + "USN: " .. device.id .. "::" .. device.urn .. "\r\n" .. "EXT:\r\n" .. + "SERVER: NodeMCU/" .. string.format("%d.%d.%d", node.info()) .. " UPnP/1.1 " .. device.name .. "/" .. device.swVersion .. "\r\n" .. + "LOCATION: http://" .. wifi.sta.getip() .. ":" .. device.http_port .. "/Device.xml\r\n\r\n" + c:send(port, ip, resp) + print("Heap: ", node.heap(), "Responded to UPnP Discovery request from " .. ip .. ":" .. port) + resp = nil + end + end +end + +return function(c, d, port, ip) + package.loaded[module] = nil + module = nil + return ssdpResponse(c, d, port, ip) +end \ No newline at end of file diff --git a/src/update.lua b/src/update.lua index 3d2f52a..5ac32ba 100644 --- a/src/update.lua +++ b/src/update.lua @@ -24,7 +24,7 @@ end) if file.exists("update_process.new") then file.rename("update_process.new", "update_process.lua") - require("variables_set").set("update_init", "{ force = true, commitish = \"v".. require("device").swVersion .. "\" }") + require("variables_set")("update_init", "{ force = true, commitish = \"v".. require("device").swVersion .. "\" }") node.restart() end diff --git a/src/update_manifest.lua b/src/update_manifest.lua index 51d4e6c..e3697f4 100644 --- a/src/update_manifest.lua +++ b/src/update_manifest.lua @@ -8,14 +8,14 @@ local download_new_manifest = function(tag_name) "https://github.com/" .. repo .. "/raw/" .. tag_name .. "/src/manifest.json", "Accept-Encoding: deflate\r\n", function(code, data) - local new_manifest = cjson.decode(data) + local new_manifest = sjson.decode(data) print("Heap: ", node.heap(), "downloaded updated manifest.json") local file_size = file.list()['manifest.json'] local current_manifest = {} -- open the existing manifest.json on the device for comparing file SHAs if file.open("manifest.json") then - current_manifest = cjson.decode(file.read(file_size)) + current_manifest = sjson.decode(file.read(file_size)) file.close() end @@ -97,7 +97,7 @@ local check_for_version_update = function() function(code, data) local latest_release_tag if code == 200 then - latest_release_tag = cjson.decode(data)["tag_name"] + latest_release_tag = sjson.decode(data)["tag_name"] end compare_github_release(latest_release_tag) end diff --git a/src/variables_build.lua b/src/variables_build.lua index fce4b2c..b421b48 100644 --- a/src/variables_build.lua +++ b/src/variables_build.lua @@ -1,16 +1,23 @@ -local me = { - build = function (objects) - local out = {} - table.insert(out, "{ ") - for i, object in pairs(objects) do - table.insert(out, "\r\n{ ") - for key, value in pairs(object) do - table.insert(out, key .. " = " .. value .. ", ") - end - table.insert(out, "},") +local module = ... + +local function build(objects) + if not objects then return nil end + + local out = {} + table.insert(out, "{ ") + for i, object in pairs(objects) do + table.insert(out, "\r\n{ ") + for key, value in pairs(object) do + table.insert(out, key .. " = " .. value .. ", ") end - table.insert(out, "}") - return table.concat(out) + table.insert(out, "},") end -} -return me \ No newline at end of file + table.insert(out, "}") + return table.concat(out) +end + +return function(objects) + package.loaded[module] = nil + module = nil + return build(objects) +end \ No newline at end of file diff --git a/src/variables_set.lua b/src/variables_set.lua index 2c2d9c1..a4f6a93 100644 --- a/src/variables_set.lua +++ b/src/variables_set.lua @@ -1,14 +1,21 @@ -local me = { - set = function (name, value) - local fn = name .. '.lua' - local f = file.open(fn, "w") - f.writeline("local " .. name .. " = " .. value) - f.writeline("return " .. name) - f.close() - node.compile(fn) - file.remove(fn) - print("Heap: ", node.heap(), "Wrote: ", fn) - collectgarbage() +local module = ... +local function set(name, value) + if not value then return end + local fn = name .. '.lua' + local f = file.open(fn, "w") + f.writeline("local " .. name .. " = " .. value) + f.writeline("return " .. name) + f.close() + node.compile(fn) + file.remove(fn) + print("Heap: ", node.heap(), "Wrote: ", fn) + collectgarbage() +end + +return function(name, value) + if package.loaded[module] then + package.loaded[module] = nil end -} -return me \ No newline at end of file + module = nil + set(name, value) +end \ No newline at end of file