diff --git a/README.md b/README.md index be835edc4..225e1874e 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,9 @@ build using: `./b.sh` you can also do advanced build by build_app.sh: -`./build_app.sh apps/ ` - +`./build_app.sh apps/ ` +(appname must be identical to foldername in apps/ folder) + e.g. `./build_app.sh apps/openbk7231app openbk7231app 1.0.0` # flashing for BK7231T @@ -70,7 +71,7 @@ Visit /ota - here start the flashing process. ## First run -At first boot, if the new formware does not find your wifi SSID and password in the Tuya flash, it will start as an access point. +At first boot, if the new firmware does not find your wifi SSID and password in the Tuya flash, it will start as an access point. The access point will come up on 192.168.4.1, however some machines may not get an ip from it - you may need to configure your connecting for a staitc IP on that network, e.g. 192.168.4.10 @@ -117,6 +118,32 @@ Get USB to UART converter, start phoenixMC.exe from OpenXR809 repository and fol It is also possible to build a part of our App for Windows platform. It basically creates a Windows .exe for our HTTP server, so developers can create our configurator, etc, pages faster, without having any Tuya modules at hand. For building on Windows, use MSVC projects in the app directory. It is using Winsock and creates a TCP listening socket on port 80, so make sure your machine has it free to use. +# Pin roles + +You can set pin roles in "Configure Module" section or use one of predefined templates from "Quick config" subpage. +For each pin, you also set coresponding channel value. This is needed for modules with multiple relays. If you have 3 relays and 3 buttons, you need to use channel values like 1, 2, and 3. Just enter '1' in the text field, etc. +Currently available pin roles: +- Button +- Button_n (as Button but pin logical value is inversed) +- Relay +- Relay_n (as Relay but pin logical value is inversed) +- LED +- LED_n (as Led but pin logical value is inversed) +- Button Toggle All - this button toggles all channels at once +- Button Toggle All_n (as above but pin logical value is inversed) +- PWM - pulse width modulation output for LED dimmers (with MQTT dimming support from Home Assistant) +- WiFi LED - special LED to indicate WLan connection state + +# Detailed flashing guides along with device teardowns + + I have prepared several detailed teardowns and flashing guides for multiple supported devices. + + Outdoor two relays smart switch CCWFIO232PK (BK7231T): + https://www.elektroda.pl/rtvforum/viewtopic.php?p=19906670#19906670 + + Qiachip Smart Switch module (BK7231N/CB2S): + https://www.elektroda.pl/rtvforum/viewtopic.php?t=3874289&highlight= + # Futher reading For technical insights and generic SDK information related to Bekken and XRadio modules, please refer: diff --git a/src/httpserver/new_http.c b/src/httpserver/new_http.c index 4a3694a4f..a8390013d 100644 --- a/src/httpserver/new_http.c +++ b/src/httpserver/new_http.c @@ -1,1405 +1,1409 @@ - - -#include "../new_common.h" -#include "ctype.h" -#if WINDOWS -//#include -#include -//#include -#elif PLATFORM_XR809 -#include "lwip/sockets.h" -#include -#include -#else -#include "lwip/sockets.h" -#include "str_pub.h" -#endif -#include "new_http.h" -#include "../new_pins.h" -#include "../new_cfg.h" -#include "../ota/ota.h" -#ifdef WINDOWS - -#elif PLATFORM_XR809 - -#elif defined(PLATFORM_BK7231N) -// tuya-iotos-embeded-sdk-wifi-ble-bk7231n/sdk/include/tuya_hal_storage.h -#include "tuya_hal_storage.h" -#include "BkDriverFlash.h" -#else -// REALLY? A typo in Tuya SDK? Storge? -// tuya-iotos-embeded-sdk-wifi-ble-bk7231t/platforms/bk7231t/tuya_os_adapter/include/driver/tuya_hal_storge.h -#include "../logging/logging.h" -#include "tuya_hal_storge.h" -#include "BkDriverFlash.h" -#endif - -/* -GET / HTTP/1.1 -Host: 127.0.0.1 -*/ -/* -GET /test?a=5 HTTP/1.1 -Host: 127.0.0.1 -*/ -/* -GET /test?a=Test%20with%20space HTTP/1.1 -Host: 127.0.0.1 -Connection: keep-alive -Cache-Control: max-age=0 -*/ -/* -GET /test?a=15&b=25 HTTP/1.1 -Host: 127.0.0.1 -Connection: keep-alive -*/ - -#define DEFAULT_OTA_URL "http://raspberrypi:1880/firmware" - -// make sure that USER_SW_VER is set on all platforms -#ifndef USER_SW_VER -#ifdef WINDOWS -#define USER_SW_VER "Win_Test" -#elif PLATFORM_XR809 -#define USER_SW_VER "XR809_Test" -#elif defined(PLATFORM_BK7231N) -#define USER_SW_VER "BK7231N_Test" -#elif defined(PLATFORM_BK7231T) -#define USER_SW_VER "BK7231T_Test" -#else -#define USER_SW_VER "unknown" - -#endif -#endif - -const char httpHeader[] = "HTTP/1.1 %d OK\nContent-type: %s" ; // HTTP header -const char httpMimeTypeHTML[] = "text/html" ; // HTML MIME type -const char httpMimeTypeText[] = "text/plain" ; // TEXT MIME type -const char httpMimeTypeJson[] = "application/json" ; // TEXT MIME type -const char httpMimeTypeBinary[] = "application/octet-stream" ; // binary/file MIME type -const char htmlHeader[] = "" ; -const char htmlEnd[] = "" ; -const char htmlReturnToMenu[] = "Return to menu";; -const char htmlReturnToCfg[] = "Return to cfg";; -const char *g_build_str = "Build on " __DATE__ " " __TIME__ " version " USER_SW_VER; // Show GIT version at Build line; - -const char httpCorsHeaders[] = "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept" ; // TEXT MIME type - -const char *methodNames[] = { - "GET", - "PUT", - "POST", - "OPTIONS" -}; - - -#if WINDOWS -#define os_free free -#define os_malloc malloc -#endif - -void misc_formatUpTimeString(int totalSeconds, char *o); -int Time_getUpTimeSeconds(); - -typedef struct http_callback_tag { - char *url; - int method; - http_callback_fn callback; -} http_callback_t; - -#define MAX_HTTP_CALLBACKS 32 -static http_callback_t *callbacks[MAX_HTTP_CALLBACKS]; -static int numCallbacks = 0; - -int HTTP_RegisterCallback( const char *url, int method, http_callback_fn callback){ - if (!url || !callback){ - return -1; - } - if (numCallbacks >= MAX_HTTP_CALLBACKS){ - return -4; - } - callbacks[numCallbacks] = (http_callback_t*)os_malloc(sizeof(http_callback_t)); - if (!callbacks[numCallbacks]){ - return -2; - } - callbacks[numCallbacks]->url = (char *)os_malloc(strlen(url)+1); - if (!callbacks[numCallbacks]->url){ - os_free(callbacks[numCallbacks]); - return -3; - } - strcpy(callbacks[numCallbacks]->url, url); - callbacks[numCallbacks]->callback = callback; - callbacks[numCallbacks]->method = method; - - numCallbacks++; - - // success - return 0; -} - -int my_strnicmp(char *a, char *b, int len){ - int i; - for (i = 0; i < len; i++){ - char x = *a; - char y = *b; - if (!x || !y) return 1; - if ((x | 0x20) != (y | 0x20)) return 1; - a++; - b++; - } - return 0; -} - -bool http_startsWith(const char *base, const char *substr) { - while(*substr != 0) { - if(*base != *substr) - return false; - if(*base == 0) - return false; - base++; - substr++; - } - return true; -} -bool http_checkUrlBase(const char *base, const char *fileName) { - while(*base != 0 && *base != '?' && *base != ' ') { - if(*base != *fileName) - return false; - if(*base == 0) - return false; - base++; - fileName++; - } - if(*fileName != 0) - return false; - return true; -} - -void http_setup(http_request_t *request, const char *type){ - hprintf128(request, httpHeader, request->responseCode, type); - poststr(request,"\r\n"); // next header - poststr(request,httpCorsHeaders); - poststr(request,"\r\n"); // end headers with double CRLF - poststr(request,"\r\n"); -} - -const char *http_checkArg(const char *p, const char *n) { - while(1) { - if(*n == 0 && (*p == 0 || *p == '=')) - return p; - if(*p != *n) - return 0; - p++; - n++; - } - return p; -} -void http_copyCarg(const char *atin, char *to, int maxSize) { - int a, b; - const unsigned char *at = (unsigned char *)atin; - - while(*at != 0 && *at != '&' && *at != ' ' && maxSize > 1) { -#if 0 - *to = *at; - to++; - at++; - maxSize--; -#else - if ((*at == '%') && - ((a = at[1]) && (b = at[2])) && - (isxdigit(a) && isxdigit(b))) { - if (a >= 'a') - a -= 'a'-'A'; - if (a >= 'A') - a -= ('A' - 10); - else - a -= '0'; - if (b >= 'a') - b -= 'a'-'A'; - if (b >= 'A') - b -= ('A' - 10); - else - b -= '0'; - *to++ = 16*a+b; - at+=3; - } else if (*at == '+') { - *to++ = ' '; - at++; - } else { - *to++ = *at++; - } - maxSize--; -#endif - } - *to = 0; -} -bool http_getArg(const char *base, const char *name, char *o, int maxSize) { - *o = '\0'; - while(*base != '?') { - if(*base == 0) - return 0; - base++; - } - base++; - while(*base) { - const char *at = http_checkArg(base,name); - if(at) { - at++; - http_copyCarg(at,o,maxSize); - return 1; - } - while(*base != '&') { - if(*base == 0) { - return 0; - } - base++; - } - base++; - } - return 0; -} - -const char *htmlIndex = ""; -/* -const char *htmlPinRoles = "\ -\ -\ -\ -\ -\ -"; -*/ - -const char *htmlPinRoleNames[] = { - " ", - "Rel", - "Rel_n", - "Btn", - "Btn_n", - "LED", - "LED_n", - "PWM", - "Wifi LED", - "Wifi LED_n", - "e", - "e", -}; - -void setupAllWB2SPinsAsButtons() { - PIN_SetPinRoleForPinIndex(6,IOR_Button); - PIN_SetPinChannelForPinIndex(6,1); - - PIN_SetPinRoleForPinIndex(7,IOR_Button); - PIN_SetPinChannelForPinIndex(7,1); - - PIN_SetPinRoleForPinIndex(8,IOR_Button); - PIN_SetPinChannelForPinIndex(8,1); - - PIN_SetPinRoleForPinIndex(23,IOR_Button); - PIN_SetPinChannelForPinIndex(23,1); - - PIN_SetPinRoleForPinIndex(24,IOR_Button); - PIN_SetPinChannelForPinIndex(24,1); - - PIN_SetPinRoleForPinIndex(26,IOR_Button); - PIN_SetPinChannelForPinIndex(26,1); - - PIN_SetPinRoleForPinIndex(27,IOR_Button); - PIN_SetPinChannelForPinIndex(27,1); -} - -typedef struct template_s { - void (*setter)(); - const char *name; -} template_t; - -template_t g_templates [] = { - { Setup_Device_Empty, "Empty"}, - // BK7231N devices - { Setup_Device_BK7231N_CB2S_QiachipSmartSwitch, "[BK7231N][CB2S] QiaChip Smart Switch"}, - // BK7231T devices - { Setup_Device_TuyaWL_SW01_16A, "WL SW01 16A"}, - { Setup_Device_TuyaSmartLife4CH10A, "Smart Life 4CH 10A"}, - { Setup_Device_IntelligentLife_NF101A, "Intelligent Life NF101A"}, - { Setup_Device_TuyaLEDDimmerSingleChannel, "Tuya LED Dimmer Single Channel PWM WB3S"}, - { Setup_Device_CalexLEDDimmerFiveChannel, "Calex RGBWW LED Dimmer Five Channel PWM BK7231S"}, - { Setup_Device_CalexPowerStrip_900018_1v1_0UK, "Calex UK power strip 900018.1 v1.0 UK"}, - { Setup_Device_ArlecCCTDownlight, "Arlec CCT LED Downlight ALD029CHA"}, - { Setup_Device_NedisWIFIPO120FWT_16A, "Nedis WIFIPO120FWT SmartPlug 16A"}, - { Setup_Device_NedisWIFIP130FWT_10A, "Nedis WIFIP130FWT SmartPlug 10A"}, - { Setup_Device_EmaxHome_EDU8774, "Emax Home EDU8774 SmartPlug 16A"}, - { Setup_Device_TuyaSmartPFW02G, "Tuya Smart PFW02-G"} -}; - -int g_total_templates = sizeof(g_templates)/sizeof(g_templates[0]); - -#if PLATFORM_XR809 -const char *g_header = "

OpenXR809

[Read more][Support project]

"; - -#elif PLATFORM_BK7231N - -const char *g_header = "

OpenBK7231N

[Read more][Support project]

"; - -#elif PLATFORM_BK7231T - -const char *g_header = "

OpenBK7231T

[Read more][Support project]

"; - -#elif WINDOWS - -const char *g_header = "

OpenBK7231 [Win test]

[Read more][Support project]

"; - -#else - -const char *g_header = "

error

"; -#error "Platform not supported" -//Platform not supported -#endif - - -void HTTP_AddBuildFooter(http_request_t *request) { - char upTimeStr[128]; - unsigned char mac[32]; - poststr(request,"
"); - poststr(request,g_build_str); - poststr(request,"
Online for "); - misc_formatUpTimeString(Time_getUpTimeSeconds(), upTimeStr); - poststr(request,upTimeStr); - - WiFI_GetMacAddress((char *)mac); - - sprintf(upTimeStr,"
Device MAC: %02X%02X%02X%02X%02X%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); - poststr(request,upTimeStr); - -} - - -// add some more output safely, sending if necessary. -// call with str == NULL to force send. - can be binary. -// supply length -int postany(http_request_t *request, const char *str, int len){ - int currentlen; - int addlen = len; - if (NULL == str){ - send(request->fd, request->reply, request->replylen, 0); - request->reply[0] = 0; - request->replylen = 0; - return 0; - } - - currentlen = request->replylen; - if (currentlen + addlen >= request->replymaxlen){ - send(request->fd, request->reply, request->replylen, 0); - request->reply[0] = 0; - request->replylen = 0; - currentlen = 0; - } - if (addlen > request->replymaxlen){ - printf("won't fit"); - } else { - memcpy( request->reply+request->replylen, str, addlen ); - request->replylen += addlen; - } - return (currentlen + addlen); -} - - -// add some more output safely, sending if necessary. -// call with str == NULL to force send. -int poststr(http_request_t *request, const char *str){ - if (str == NULL){ - return postany(request, NULL, 0); - } - return postany(request, str, strlen(str)); -} - -void misc_formatUpTimeString(int totalSeconds, char *o) { - int rem_days; - int rem_hours; - int rem_minutes; - int rem_seconds; - - rem_days = totalSeconds / (24*60*60); - totalSeconds = totalSeconds % (24*60*60); - rem_hours = totalSeconds / (60*60); - totalSeconds = totalSeconds % (60*60); - rem_minutes = totalSeconds / (60); - rem_seconds = totalSeconds % 60; - - *o = 0; - if(rem_days > 0) - { - sprintf(o,"%i days, %i hours, %i minutes and %i seconds ",rem_days,rem_hours,rem_minutes,rem_seconds); - } - else if(rem_hours > 0) - { - sprintf(o,"%i hours, %i minutes and %i seconds ",rem_hours,rem_minutes,rem_seconds); - } - else if(rem_minutes > 0) - { - sprintf(o,"%i minutes and %i seconds ",rem_minutes,rem_seconds); - } - else - { - sprintf(o,"just %i seconds ",rem_seconds); - } -} - -int hprintf128(http_request_t *request, const char *fmt, ...){ - va_list argList; - //BaseType_t taken; - char tmp[128]; - va_start(argList, fmt); - vsprintf(tmp, fmt, argList); - va_end(argList); - return postany(request, tmp, strlen(tmp)); -} - -uint8_t hexdigit( char hex ) -{ - return (hex <= '9') ? hex - '0' : - toupper(hex) - 'A' + 10 ; -} - -uint8_t hexbyte( const char* hex ) -{ - return (hexdigit(*hex) << 4) | hexdigit(*(hex+1)) ; -} - -int HTTP_ProcessPacket(http_request_t *request) { - int i, j, k; - char tmpA[128]; - char tmpB[64]; - char tmpC[64]; - char *p; - char *headers; - char *protocol; - //int bChanged = 0; - char *urlStr = ""; - - char *recvbuf = request->received; - for ( i = 0; i < sizeof(methodNames)/sizeof(*methodNames); i++){ - if (http_startsWith(recvbuf, methodNames[i])){ - urlStr = recvbuf + strlen(methodNames[i]) + 2; // skip method name plus space, plus slash - request->method = i; - break; - } - } - if (request->method == -1){ - printf("unsupported method %7s", recvbuf); - return 0; - } - - if (request->method == HTTP_GET) { - printf("HTTP request\n"); - } else { - printf("Other request\n"); - } - - // if OPTIONS, return now - for CORS - if (request->method == HTTP_OPTIONS) { - http_setup(request, httpMimeTypeHTML); - i = strlen(request->reply); - return i; - } - - // chop URL at space - p = strchr(urlStr, ' '); - if (*p) { - *p = '\0'; - p++; // past space - } - else { - printf("invalid request\n"); - return 0; - } - - request->url = urlStr; - - // protocol is next, termed by \r\n - protocol = p; - p = strchr(protocol, '\r'); - if (*p) { - *p = '\0'; - p++; // past \r - p++; // past \n - } else { - printf("invalid request\n"); - return 0; - } - // i.e. not received - request->contentLength = -1; - headers = p; - do { - p = strchr(headers, '\r'); - if (p != headers){ - if (p){ - if (request->numheaders < 16){ - request->headers[request->numheaders] = headers; - request->numheaders++; - } - // pick out contentLength - if (!my_strnicmp(headers, "Content-Length:", 15)){ - request->contentLength = atoi(headers + 15); - } - - *p = 0; - p++; // past \r - p++; // past \n - headers = p; - } else { - break; - } - } - if (*p == '\r'){ - // end of headers - *p = 0; - p++; - p++; - break; - } - } while(1); - - request->bodystart = p; - request->bodylen = request->receivedLen - (p - request->received); - - // we will make this more general - http_getArg(urlStr,"a",tmpA,sizeof(tmpA)); - http_getArg(urlStr,"b",tmpB,sizeof(tmpB)); - http_getArg(urlStr,"c",tmpC,sizeof(tmpC)); - if (*tmpA){ - request->querynames[request->numqueryitems] = "a"; - request->queryvalues[request->numqueryitems] = tmpA; - request->numqueryitems++; - } - if (*tmpB){ - request->querynames[request->numqueryitems] = "b"; - request->queryvalues[request->numqueryitems] = tmpB; - request->numqueryitems++; - } - if (*tmpC){ - request->querynames[request->numqueryitems] = "c"; - request->queryvalues[request->numqueryitems] = tmpC; - request->numqueryitems++; - } - - - // look for a callback with this URL and method, or HTTP_ANY - for (i = 0; i < numCallbacks; i++){ - char *url = callbacks[i]->url; - if (http_startsWith(urlStr, &url[1])){ - int method = callbacks[i]->method; - if(method == HTTP_ANY || method == request->method){ - return callbacks[i]->callback(request); - } - } - } - - if(http_checkUrlBase(urlStr,"about")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - poststr(request,"About us page."); - poststr(request,htmlReturnToMenu); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_mqtt")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - poststr(request,"

Use this to connect to your MQTT

"); - poststr(request,"
\ -
\ -
\ -
\ -

\ -
\ -
\ -
\ -
\ -
\ -
\ - \ -
"); - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_mqtt_set")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - - if(http_getArg(urlStr,"host",tmpA,sizeof(tmpA))) { - CFG_SetMQTTHost(tmpA); - } - if(http_getArg(urlStr,"port",tmpA,sizeof(tmpA))) { - CFG_SetMQTTPort(atoi(tmpA)); - } - if(http_getArg(urlStr,"user",tmpA,sizeof(tmpA))) { - CFG_SetMQTTUserName(tmpA); - } - if(http_getArg(urlStr,"password",tmpA,sizeof(tmpA))) { - CFG_SetMQTTPass(tmpA); - } - if(http_getArg(urlStr,"client",tmpA,sizeof(tmpA))) { - CFG_SetMQTTBrokerName(tmpA); - } - if(CFG_SaveMQTT()) { - poststr(request,"MQTT mode set!"); - } else { - poststr(request,"Error saving MQTT settings to flash!"); - } - - - poststr(request,"Please wait for module to connect... if there is problem, restart it..."); - - poststr(request,"
"); - poststr(request,"Return to MQTT settings"); - poststr(request,"
"); - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_webapp")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - poststr(request,"

Use this to set the URL of the Webapp

"); - poststr(request,"
\ -
\ -
\ - \ -
"); - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"config_dump_table")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); -#if WINDOWS - poststr(request,"Not implemented
"); -#elif PLATFORM_XR809 - poststr(request,"Not implemented
"); -#else - poststr(request,"Dumped to log
"); - config_dump_table(); -#endif - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_webapp_set")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - - if(http_getArg(urlStr,"url",tmpA,sizeof(tmpA))) { - if(CFG_SetWebappRoot(tmpA)) { - hprintf128(request,"Webapp url set to %s", tmpA); - } else { - hprintf128(request,"Webapp url change error - failed to save to flash."); - } - } else { - poststr(request,"Webapp url not set because you didn't specify the argument."); - } - - poststr(request,"
"); - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_wifi_set")) { - printf("HTTP_ProcessPacket: generating cfg_wifi_set \r\n"); - - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - if(http_getArg(recvbuf,"open",tmpA,sizeof(tmpA))) { - CFG_SetWiFiSSID(""); - CFG_SetWiFiPass(""); - poststr(request,"WiFi mode set: open access point."); - } else { - if(http_getArg(urlStr,"ssid",tmpA,sizeof(tmpA))) { - CFG_SetWiFiSSID(tmpA); - } - if(http_getArg(urlStr,"pass",tmpA,sizeof(tmpA))) { - CFG_SetWiFiPass(tmpA); - } - poststr(request,"WiFi mode set: connect to WLAN."); - } - printf("HTTP_ProcessPacket: calling CFG_SaveWiFi \r\n"); - CFG_SaveWiFi(); - printf("HTTP_ProcessPacket: done CFG_SaveWiFi \r\n"); - - poststr(request,"Please wait for module to reset..."); - - poststr(request,"
"); - poststr(request,"Return to WiFi settings"); - poststr(request,"
"); - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_loglevel_set")) { - printf("HTTP_ProcessPacket: generating cfg_loglevel_set \r\n"); - - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - if(http_getArg(recvbuf,"loglevel",tmpA,sizeof(tmpA))) { -#if PLATFORM_BK7231T - loglevel = atoi(tmpA); -#endif - poststr(request,"LOG level changed."); - } - poststr(request,"
\ -
\ -

\ - \ -
"); - - poststr(request,"
"); - poststr(request,"Return to config settings"); - poststr(request,"
"); - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_wifi")) { - // for a test, show password as well... - const char *cur_ssid, *cur_pass; - - - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - /*bChanged = 0; - if(http_getArg(recvbuf,"ssid",tmpA,sizeof(tmpA))) { - CFG_SetWiFiSSID(tmpA); - poststr(request,"

WiFi SSID set!

"); - bChanged = 1; - } - if(http_getArg(recvbuf,"pass",tmpA,sizeof(tmpA))) { - CFG_SetWiFiPass(tmpA); - poststr(request,"

WiFi Password set!

"); - bChanged = 1; - } - if(bChanged) { - poststr(request,"

Device will reconnect after restarting

"); - }*/ - poststr(request,"

Check networks reachable by module

This will lag few seconds.
"); - if(http_getArg(urlStr,"scan",tmpA,sizeof(tmpA))) { -#ifdef WINDOWS - - poststr(request,"Not available on Windows
"); -#elif PLATFORM_XR809 - poststr(request,"TODO XR809
"); - -#elif PLATFORM_BK7231T - AP_IF_S *ar; - uint32_t num; - - bk_printf("Scan begin...\r\n"); - tuya_hal_wifi_all_ap_scan(&ar,&num); - bk_printf("Scan returned %i networks\r\n",num); - for(i = 0; i < num; i++) { - sprintf(tmpA,"[%i/%i] SSID: %s, Channel: %i, Signal %i
",i,(int)num,ar[i].ssid, ar[i].channel, ar[i].rssi); - poststr(request,tmpA); - } - tuya_hal_wifi_release_ap(ar); -#elif PLATFORM_BK7231N - poststr(request,"TODO: BK7231N support for scan
"); - -#else -#error "Unknown platform" - poststr(request,"Unknown platform
"); -#endif - } - poststr(request,"
\ - \ - \ -
"); - poststr(request,"

Use this to disconnect from your WiFi

"); - poststr(request,"
\ - \ - \ -
"); - poststr(request,"

Use this to connect to your WiFi

"); - poststr(request,"
\ -
\ -
\ -
\ -

\ - \ -
"); - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_mac")) { - // must be unsigned, else print below prints negatives as e.g. FFFFFFFe - unsigned char mac[6]; - - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - - if(http_getArg(recvbuf,"mac",tmpA,sizeof(tmpA))) { - for( i = 0; i < 6; i++ ) - { - mac[i] = hexbyte( &tmpA[i * 2] ) ; - } - //sscanf(tmpA,"%02X%02X%02X%02X%02X%02X",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]); - if(WiFI_SetMacAddress((char*)mac)) { - poststr(request,"

New MAC set!

"); - } else { - poststr(request,"

MAC change error?

"); - } - } - - WiFI_GetMacAddress((char *)mac); - - sprintf(tmpA,"%02X%02X%02X%02X%02X%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); - - poststr(request,"

Here you can change MAC address.

"); - poststr(request,"
\ -
\ -

\ - \ -
"); - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"flash_read_tool")) { - int len = 16; - int ofs = 1970176; - int res; - int rem; - int now; - int nowOfs; - int hex; - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - poststr(request,"

Flash Read Tool

"); - if( http_getArg(urlStr,"hex",tmpA,sizeof(tmpA))){ - hex = atoi(tmpA); - } else { - hex = 0; - } - - if( http_getArg(urlStr,"offset",tmpA,sizeof(tmpA)) && - http_getArg(urlStr,"len",tmpB,sizeof(tmpB))) { - u8 buffer[128]; - len = atoi(tmpB); - ofs = atoi(tmpA); - sprintf(tmpA,"Memory at %i with len %i reads: ",ofs,len); - poststr(request,tmpA); - poststr(request,"
"); - - ///res = bekken_hal_flash_read (ofs, buffer,len); - //sprintf(tmpA,"Result %i",res); - // strcat(outbuf,tmpA); - /// strcat(outbuf,"
"); - - nowOfs = ofs; - rem = len; - while(1) { - if(rem > sizeof(buffer)) { - now = sizeof(buffer); - } else { - now = rem; - } -#if PLATFORM_XR809 - //uint32_t flash_read(uint32_t flash, uint32_t addr,void *buf, uint32_t size) - #define FLASH_INDEX_XR809 0 - res = flash_read(FLASH_INDEX_XR809, nowOfs, buffer, now); -#else - res = bekken_hal_flash_read (nowOfs, buffer,now); -#endif - for(i = 0; i < now; i++) { - u8 val = buffer[i]; - if(!hex && isprint(val)) { - sprintf(tmpA,"'%c' ",val); - } else { - sprintf(tmpA,"%02X ",val); - } - poststr(request,tmpA); - } - rem -= now; - nowOfs += now; - if(rem <= 0) { - break; - } - } - - poststr(request,"
"); - } - poststr(request,"
"); + + +#include "../new_common.h" +#include "ctype.h" +#if WINDOWS +//#include +#include +//#include +#elif PLATFORM_XR809 +#include "lwip/sockets.h" +#include +#include +#else +#include "lwip/sockets.h" +#include "str_pub.h" +#endif +#include "new_http.h" +#include "../new_pins.h" +#include "../new_cfg.h" +#include "../ota/ota.h" +#ifdef WINDOWS + +#elif PLATFORM_XR809 + +#elif defined(PLATFORM_BK7231N) +// tuya-iotos-embeded-sdk-wifi-ble-bk7231n/sdk/include/tuya_hal_storage.h +#include "tuya_hal_storage.h" +#include "BkDriverFlash.h" +#else +// REALLY? A typo in Tuya SDK? Storge? +// tuya-iotos-embeded-sdk-wifi-ble-bk7231t/platforms/bk7231t/tuya_os_adapter/include/driver/tuya_hal_storge.h +#include "../logging/logging.h" +#include "tuya_hal_storge.h" +#include "BkDriverFlash.h" +#endif + +/* +GET / HTTP/1.1 +Host: 127.0.0.1 +*/ +/* +GET /test?a=5 HTTP/1.1 +Host: 127.0.0.1 +*/ +/* +GET /test?a=Test%20with%20space HTTP/1.1 +Host: 127.0.0.1 +Connection: keep-alive +Cache-Control: max-age=0 +*/ +/* +GET /test?a=15&b=25 HTTP/1.1 +Host: 127.0.0.1 +Connection: keep-alive +*/ + +#define DEFAULT_OTA_URL "http://raspberrypi:1880/firmware" + +// make sure that USER_SW_VER is set on all platforms +#ifndef USER_SW_VER +#ifdef WINDOWS +#define USER_SW_VER "Win_Test" +#elif PLATFORM_XR809 +#define USER_SW_VER "XR809_Test" +#elif defined(PLATFORM_BK7231N) +#define USER_SW_VER "BK7231N_Test" +#elif defined(PLATFORM_BK7231T) +#define USER_SW_VER "BK7231T_Test" +#else +#define USER_SW_VER "unknown" + +#endif +#endif + +const char httpHeader[] = "HTTP/1.1 %d OK\nContent-type: %s" ; // HTTP header +const char httpMimeTypeHTML[] = "text/html" ; // HTML MIME type +const char httpMimeTypeText[] = "text/plain" ; // TEXT MIME type +const char httpMimeTypeJson[] = "application/json" ; // TEXT MIME type +const char httpMimeTypeBinary[] = "application/octet-stream" ; // binary/file MIME type +const char htmlHeader[] = "" ; +const char htmlEnd[] = "" ; +const char htmlReturnToMenu[] = "Return to menu";; +const char htmlReturnToCfg[] = "Return to cfg";; +const char *g_build_str = "Build on " __DATE__ " " __TIME__ " version " USER_SW_VER; // Show GIT version at Build line; + +const char httpCorsHeaders[] = "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept" ; // TEXT MIME type + +const char *methodNames[] = { + "GET", + "PUT", + "POST", + "OPTIONS" +}; + + +#if WINDOWS +#define os_free free +#define os_malloc malloc +#endif + +void misc_formatUpTimeString(int totalSeconds, char *o); +int Time_getUpTimeSeconds(); + +typedef struct http_callback_tag { + char *url; + int method; + http_callback_fn callback; +} http_callback_t; + +#define MAX_HTTP_CALLBACKS 32 +static http_callback_t *callbacks[MAX_HTTP_CALLBACKS]; +static int numCallbacks = 0; + +int HTTP_RegisterCallback( const char *url, int method, http_callback_fn callback){ + if (!url || !callback){ + return -1; + } + if (numCallbacks >= MAX_HTTP_CALLBACKS){ + return -4; + } + callbacks[numCallbacks] = (http_callback_t*)os_malloc(sizeof(http_callback_t)); + if (!callbacks[numCallbacks]){ + return -2; + } + callbacks[numCallbacks]->url = (char *)os_malloc(strlen(url)+1); + if (!callbacks[numCallbacks]->url){ + os_free(callbacks[numCallbacks]); + return -3; + } + strcpy(callbacks[numCallbacks]->url, url); + callbacks[numCallbacks]->callback = callback; + callbacks[numCallbacks]->method = method; + + numCallbacks++; + + // success + return 0; +} + +int my_strnicmp(char *a, char *b, int len){ + int i; + for (i = 0; i < len; i++){ + char x = *a; + char y = *b; + if (!x || !y) return 1; + if ((x | 0x20) != (y | 0x20)) return 1; + a++; + b++; + } + return 0; +} + +bool http_startsWith(const char *base, const char *substr) { + while(*substr != 0) { + if(*base != *substr) + return false; + if(*base == 0) + return false; + base++; + substr++; + } + return true; +} +bool http_checkUrlBase(const char *base, const char *fileName) { + while(*base != 0 && *base != '?' && *base != ' ') { + if(*base != *fileName) + return false; + if(*base == 0) + return false; + base++; + fileName++; + } + if(*fileName != 0) + return false; + return true; +} + +void http_setup(http_request_t *request, const char *type){ + hprintf128(request, httpHeader, request->responseCode, type); + poststr(request,"\r\n"); // next header + poststr(request,httpCorsHeaders); + poststr(request,"\r\n"); // end headers with double CRLF + poststr(request,"\r\n"); +} + +const char *http_checkArg(const char *p, const char *n) { + while(1) { + if(*n == 0 && (*p == 0 || *p == '=')) + return p; + if(*p != *n) + return 0; + p++; + n++; + } + return p; +} +void http_copyCarg(const char *atin, char *to, int maxSize) { + int a, b; + const unsigned char *at = (unsigned char *)atin; + + while(*at != 0 && *at != '&' && *at != ' ' && maxSize > 1) { +#if 0 + *to = *at; + to++; + at++; + maxSize--; +#else + if ((*at == '%') && + ((a = at[1]) && (b = at[2])) && + (isxdigit(a) && isxdigit(b))) { + if (a >= 'a') + a -= 'a'-'A'; + if (a >= 'A') + a -= ('A' - 10); + else + a -= '0'; + if (b >= 'a') + b -= 'a'-'A'; + if (b >= 'A') + b -= ('A' - 10); + else + b -= '0'; + *to++ = 16*a+b; + at+=3; + } else if (*at == '+') { + *to++ = ' '; + at++; + } else { + *to++ = *at++; + } + maxSize--; +#endif + } + *to = 0; +} +bool http_getArg(const char *base, const char *name, char *o, int maxSize) { + *o = '\0'; + while(*base != '?') { + if(*base == 0) + return 0; + base++; + } + base++; + while(*base) { + const char *at = http_checkArg(base,name); + if(at) { + at++; + http_copyCarg(at,o,maxSize); + return 1; + } + while(*base != '&') { + if(*base == 0) { + return 0; + } + base++; + } + base++; + } + return 0; +} + +const char *htmlIndex = ""; +/* +const char *htmlPinRoles = "\ +\ +\ +\ +\ +\ +"; +*/ + +const char *htmlPinRoleNames[] = { + " ", + "Rel", + "Rel_n", + "Btn", + "Btn_n", + "LED", + "LED_n", + "PWM", + "Wifi LED", + "Wifi LED_n", + "Btn_Tgl_All", + "Btn_Tgl_All_n", + "e", + "e", +}; + +void setupAllWB2SPinsAsButtons() { + PIN_SetPinRoleForPinIndex(6,IOR_Button); + PIN_SetPinChannelForPinIndex(6,1); + + PIN_SetPinRoleForPinIndex(7,IOR_Button); + PIN_SetPinChannelForPinIndex(7,1); + + PIN_SetPinRoleForPinIndex(8,IOR_Button); + PIN_SetPinChannelForPinIndex(8,1); + + PIN_SetPinRoleForPinIndex(23,IOR_Button); + PIN_SetPinChannelForPinIndex(23,1); + + PIN_SetPinRoleForPinIndex(24,IOR_Button); + PIN_SetPinChannelForPinIndex(24,1); + + PIN_SetPinRoleForPinIndex(26,IOR_Button); + PIN_SetPinChannelForPinIndex(26,1); + + PIN_SetPinRoleForPinIndex(27,IOR_Button); + PIN_SetPinChannelForPinIndex(27,1); +} + +typedef struct template_s { + void (*setter)(); + const char *name; +} template_t; + +template_t g_templates [] = { + { Setup_Device_Empty, "Empty"}, + // BK7231N devices + { Setup_Device_BK7231N_CB2S_QiachipSmartSwitch, "[BK7231N][CB2S] QiaChip Smart Switch"}, + // BK7231T devices + { Setup_Device_BK7231T_WB2S_QiachipSmartSwitch, "[BK7231T][WB2S] QiaChip Smart Switch"}, + { Setup_Device_TuyaWL_SW01_16A, "WL SW01 16A"}, + { Setup_Device_TuyaSmartLife4CH10A, "Smart Life 4CH 10A"}, + { Setup_Device_IntelligentLife_NF101A, "Intelligent Life NF101A"}, + { Setup_Device_TuyaLEDDimmerSingleChannel, "Tuya LED Dimmer Single Channel PWM WB3S"}, + { Setup_Device_CalexLEDDimmerFiveChannel, "Calex RGBWW LED Dimmer Five Channel PWM BK7231S"}, + { Setup_Device_CalexPowerStrip_900018_1v1_0UK, "Calex UK power strip 900018.1 v1.0 UK"}, + { Setup_Device_ArlecCCTDownlight, "Arlec CCT LED Downlight ALD029CHA"}, + { Setup_Device_NedisWIFIPO120FWT_16A, "Nedis WIFIPO120FWT SmartPlug 16A"}, + { Setup_Device_NedisWIFIP130FWT_10A, "Nedis WIFIP130FWT SmartPlug 10A"}, + { Setup_Device_BK7231T_Raw_PrimeWiFiSmartOutletsOutdoor_CCWFIO232PK, "Prime SmartOutlet Outdoor 2x Costco"}, + { Setup_Device_EmaxHome_EDU8774, "Emax Home EDU8774 SmartPlug 16A"}, + { Setup_Device_TuyaSmartPFW02G, "Tuya Smart PFW02-G"} +}; + +int g_total_templates = sizeof(g_templates)/sizeof(g_templates[0]); + +#if PLATFORM_XR809 +const char *g_header = "

OpenXR809

[Read more][Support project]

"; + +#elif PLATFORM_BK7231N + +const char *g_header = "

OpenBK7231N

[Read more][Support project]

"; + +#elif PLATFORM_BK7231T + +const char *g_header = "

OpenBK7231T

[Read more][Support project]

"; + +#elif WINDOWS + +const char *g_header = "

OpenBK7231 [Win test]

[Read more][Support project]

"; + +#else + +const char *g_header = "

error

"; +#error "Platform not supported" +//Platform not supported +#endif + + +void HTTP_AddBuildFooter(http_request_t *request) { + char upTimeStr[128]; + unsigned char mac[32]; + poststr(request,"
"); + poststr(request,g_build_str); + poststr(request,"
Online for "); + misc_formatUpTimeString(Time_getUpTimeSeconds(), upTimeStr); + poststr(request,upTimeStr); + + WiFI_GetMacAddress((char *)mac); + + sprintf(upTimeStr,"
Device MAC: %02X%02X%02X%02X%02X%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); + poststr(request,upTimeStr); + +} + + +// add some more output safely, sending if necessary. +// call with str == NULL to force send. - can be binary. +// supply length +int postany(http_request_t *request, const char *str, int len){ + int currentlen; + int addlen = len; + if (NULL == str){ + send(request->fd, request->reply, request->replylen, 0); + request->reply[0] = 0; + request->replylen = 0; + return 0; + } + + currentlen = request->replylen; + if (currentlen + addlen >= request->replymaxlen){ + send(request->fd, request->reply, request->replylen, 0); + request->reply[0] = 0; + request->replylen = 0; + currentlen = 0; + } + if (addlen > request->replymaxlen){ + printf("won't fit"); + } else { + memcpy( request->reply+request->replylen, str, addlen ); + request->replylen += addlen; + } + return (currentlen + addlen); +} + + +// add some more output safely, sending if necessary. +// call with str == NULL to force send. +int poststr(http_request_t *request, const char *str){ + if (str == NULL){ + return postany(request, NULL, 0); + } + return postany(request, str, strlen(str)); +} + +void misc_formatUpTimeString(int totalSeconds, char *o) { + int rem_days; + int rem_hours; + int rem_minutes; + int rem_seconds; + + rem_days = totalSeconds / (24*60*60); + totalSeconds = totalSeconds % (24*60*60); + rem_hours = totalSeconds / (60*60); + totalSeconds = totalSeconds % (60*60); + rem_minutes = totalSeconds / (60); + rem_seconds = totalSeconds % 60; + + *o = 0; + if(rem_days > 0) + { + sprintf(o,"%i days, %i hours, %i minutes and %i seconds ",rem_days,rem_hours,rem_minutes,rem_seconds); + } + else if(rem_hours > 0) + { + sprintf(o,"%i hours, %i minutes and %i seconds ",rem_hours,rem_minutes,rem_seconds); + } + else if(rem_minutes > 0) + { + sprintf(o,"%i minutes and %i seconds ",rem_minutes,rem_seconds); + } + else + { + sprintf(o,"just %i seconds ",rem_seconds); + } +} + +int hprintf128(http_request_t *request, const char *fmt, ...){ + va_list argList; + //BaseType_t taken; + char tmp[128]; + va_start(argList, fmt); + vsprintf(tmp, fmt, argList); + va_end(argList); + return postany(request, tmp, strlen(tmp)); +} + +uint8_t hexdigit( char hex ) +{ + return (hex <= '9') ? hex - '0' : + toupper(hex) - 'A' + 10 ; +} + +uint8_t hexbyte( const char* hex ) +{ + return (hexdigit(*hex) << 4) | hexdigit(*(hex+1)) ; +} + +int HTTP_ProcessPacket(http_request_t *request) { + int i, j, k; + char tmpA[128]; + char tmpB[64]; + char tmpC[64]; + char *p; + char *headers; + char *protocol; + //int bChanged = 0; + char *urlStr = ""; + + char *recvbuf = request->received; + for ( i = 0; i < sizeof(methodNames)/sizeof(*methodNames); i++){ + if (http_startsWith(recvbuf, methodNames[i])){ + urlStr = recvbuf + strlen(methodNames[i]) + 2; // skip method name plus space, plus slash + request->method = i; + break; + } + } + if (request->method == -1){ + printf("unsupported method %7s", recvbuf); + return 0; + } + + if (request->method == HTTP_GET) { + printf("HTTP request\n"); + } else { + printf("Other request\n"); + } + + // if OPTIONS, return now - for CORS + if (request->method == HTTP_OPTIONS) { + http_setup(request, httpMimeTypeHTML); + i = strlen(request->reply); + return i; + } + + // chop URL at space + p = strchr(urlStr, ' '); + if (*p) { + *p = '\0'; + p++; // past space + } + else { + printf("invalid request\n"); + return 0; + } + + request->url = urlStr; + + // protocol is next, termed by \r\n + protocol = p; + p = strchr(protocol, '\r'); + if (*p) { + *p = '\0'; + p++; // past \r + p++; // past \n + } else { + printf("invalid request\n"); + return 0; + } + // i.e. not received + request->contentLength = -1; + headers = p; + do { + p = strchr(headers, '\r'); + if (p != headers){ + if (p){ + if (request->numheaders < 16){ + request->headers[request->numheaders] = headers; + request->numheaders++; + } + // pick out contentLength + if (!my_strnicmp(headers, "Content-Length:", 15)){ + request->contentLength = atoi(headers + 15); + } + + *p = 0; + p++; // past \r + p++; // past \n + headers = p; + } else { + break; + } + } + if (*p == '\r'){ + // end of headers + *p = 0; + p++; + p++; + break; + } + } while(1); + + request->bodystart = p; + request->bodylen = request->receivedLen - (p - request->received); + + // we will make this more general + http_getArg(urlStr,"a",tmpA,sizeof(tmpA)); + http_getArg(urlStr,"b",tmpB,sizeof(tmpB)); + http_getArg(urlStr,"c",tmpC,sizeof(tmpC)); + if (*tmpA){ + request->querynames[request->numqueryitems] = "a"; + request->queryvalues[request->numqueryitems] = tmpA; + request->numqueryitems++; + } + if (*tmpB){ + request->querynames[request->numqueryitems] = "b"; + request->queryvalues[request->numqueryitems] = tmpB; + request->numqueryitems++; + } + if (*tmpC){ + request->querynames[request->numqueryitems] = "c"; + request->queryvalues[request->numqueryitems] = tmpC; + request->numqueryitems++; + } + + + // look for a callback with this URL and method, or HTTP_ANY + for (i = 0; i < numCallbacks; i++){ + char *url = callbacks[i]->url; + if (http_startsWith(urlStr, &url[1])){ + int method = callbacks[i]->method; + if(method == HTTP_ANY || method == request->method){ + return callbacks[i]->callback(request); + } + } + } + + if(http_checkUrlBase(urlStr,"about")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + poststr(request,"About us page."); + poststr(request,htmlReturnToMenu); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_mqtt")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + poststr(request,"

Use this to connect to your MQTT

"); + poststr(request,"\ +
\ +
\ +
\ +

\ +
\ +
\ +
\ +
\ +
\ +
\ + \ + "); + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_mqtt_set")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + + if(http_getArg(urlStr,"host",tmpA,sizeof(tmpA))) { + CFG_SetMQTTHost(tmpA); + } + if(http_getArg(urlStr,"port",tmpA,sizeof(tmpA))) { + CFG_SetMQTTPort(atoi(tmpA)); + } + if(http_getArg(urlStr,"user",tmpA,sizeof(tmpA))) { + CFG_SetMQTTUserName(tmpA); + } + if(http_getArg(urlStr,"password",tmpA,sizeof(tmpA))) { + CFG_SetMQTTPass(tmpA); + } + if(http_getArg(urlStr,"client",tmpA,sizeof(tmpA))) { + CFG_SetMQTTBrokerName(tmpA); + } + if(CFG_SaveMQTT()) { + poststr(request,"MQTT mode set!"); + } else { + poststr(request,"Error saving MQTT settings to flash!"); + } + + + poststr(request,"Please wait for module to connect... if there is problem, restart it..."); + + poststr(request,"
"); + poststr(request,"Return to MQTT settings"); + poststr(request,"
"); + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_webapp")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + poststr(request,"

Use this to set the URL of the Webapp

"); + poststr(request,"
\ +
\ +
\ + \ +
"); + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"config_dump_table")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); +#if WINDOWS + poststr(request,"Not implemented
"); +#elif PLATFORM_XR809 + poststr(request,"Not implemented
"); +#else + poststr(request,"Dumped to log
"); + config_dump_table(); +#endif + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_webapp_set")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + + if(http_getArg(urlStr,"url",tmpA,sizeof(tmpA))) { + if(CFG_SetWebappRoot(tmpA)) { + hprintf128(request,"Webapp url set to %s", tmpA); + } else { + hprintf128(request,"Webapp url change error - failed to save to flash."); + } + } else { + poststr(request,"Webapp url not set because you didn't specify the argument."); + } + + poststr(request,"
"); + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_wifi_set")) { + printf("HTTP_ProcessPacket: generating cfg_wifi_set \r\n"); + + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + if(http_getArg(recvbuf,"open",tmpA,sizeof(tmpA))) { + CFG_SetWiFiSSID(""); + CFG_SetWiFiPass(""); + poststr(request,"WiFi mode set: open access point."); + } else { + if(http_getArg(urlStr,"ssid",tmpA,sizeof(tmpA))) { + CFG_SetWiFiSSID(tmpA); + } + if(http_getArg(urlStr,"pass",tmpA,sizeof(tmpA))) { + CFG_SetWiFiPass(tmpA); + } + poststr(request,"WiFi mode set: connect to WLAN."); + } + printf("HTTP_ProcessPacket: calling CFG_SaveWiFi \r\n"); + CFG_SaveWiFi(); + printf("HTTP_ProcessPacket: done CFG_SaveWiFi \r\n"); + + poststr(request,"Please wait for module to reset..."); + + poststr(request,"
"); + poststr(request,"Return to WiFi settings"); + poststr(request,"
"); + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_loglevel_set")) { + printf("HTTP_ProcessPacket: generating cfg_loglevel_set \r\n"); + + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + if(http_getArg(recvbuf,"loglevel",tmpA,sizeof(tmpA))) { +#if PLATFORM_BK7231T + loglevel = atoi(tmpA); +#endif + poststr(request,"LOG level changed."); + } + poststr(request,"
\ +
\ +

\ + \ +
"); + + poststr(request,"
"); + poststr(request,"Return to config settings"); + poststr(request,"
"); + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_wifi")) { + // for a test, show password as well... + const char *cur_ssid, *cur_pass; + + + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + /*bChanged = 0; + if(http_getArg(recvbuf,"ssid",tmpA,sizeof(tmpA))) { + CFG_SetWiFiSSID(tmpA); + poststr(request,"

WiFi SSID set!

"); + bChanged = 1; + } + if(http_getArg(recvbuf,"pass",tmpA,sizeof(tmpA))) { + CFG_SetWiFiPass(tmpA); + poststr(request,"

WiFi Password set!

"); + bChanged = 1; + } + if(bChanged) { + poststr(request,"

Device will reconnect after restarting

"); + }*/ + poststr(request,"

Check networks reachable by module

This will lag few seconds.
"); + if(http_getArg(urlStr,"scan",tmpA,sizeof(tmpA))) { +#ifdef WINDOWS + + poststr(request,"Not available on Windows
"); +#elif PLATFORM_XR809 + poststr(request,"TODO XR809
"); + +#elif PLATFORM_BK7231T + AP_IF_S *ar; + uint32_t num; + + bk_printf("Scan begin...\r\n"); + tuya_hal_wifi_all_ap_scan(&ar,&num); + bk_printf("Scan returned %i networks\r\n",num); + for(i = 0; i < num; i++) { + sprintf(tmpA,"[%i/%i] SSID: %s, Channel: %i, Signal %i
",i,(int)num,ar[i].ssid, ar[i].channel, ar[i].rssi); + poststr(request,tmpA); + } + tuya_hal_wifi_release_ap(ar); +#elif PLATFORM_BK7231N + poststr(request,"TODO: BK7231N support for scan
"); + +#else +#error "Unknown platform" + poststr(request,"Unknown platform
"); +#endif + } + poststr(request,"
\ + \ + \ +
"); + poststr(request,"

Use this to disconnect from your WiFi

"); + poststr(request,"
\ + \ + \ +
"); + poststr(request,"

Use this to connect to your WiFi

"); + poststr(request,"
\ +
\ +
\ +
\ +

\ + \ +
"); + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_mac")) { + // must be unsigned, else print below prints negatives as e.g. FFFFFFFe + unsigned char mac[6]; + + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + + if(http_getArg(recvbuf,"mac",tmpA,sizeof(tmpA))) { + for( i = 0; i < 6; i++ ) + { + mac[i] = hexbyte( &tmpA[i * 2] ) ; + } + //sscanf(tmpA,"%02X%02X%02X%02X%02X%02X",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]); + if(WiFI_SetMacAddress((char*)mac)) { + poststr(request,"

New MAC set!

"); + } else { + poststr(request,"

MAC change error?

"); + } + } + + WiFI_GetMacAddress((char *)mac); + + sprintf(tmpA,"%02X%02X%02X%02X%02X%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); + + poststr(request,"

Here you can change MAC address.

"); + poststr(request,"
\ +
\ +

\ + \ +
"); + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"flash_read_tool")) { + int len = 16; + int ofs = 1970176; + int res; + int rem; + int now; + int nowOfs; + int hex; + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + poststr(request,"

Flash Read Tool

"); + if( http_getArg(urlStr,"hex",tmpA,sizeof(tmpA))){ + hex = atoi(tmpA); + } else { + hex = 0; + } + + if( http_getArg(urlStr,"offset",tmpA,sizeof(tmpA)) && + http_getArg(urlStr,"len",tmpB,sizeof(tmpB))) { + u8 buffer[128]; + len = atoi(tmpB); + ofs = atoi(tmpA); + sprintf(tmpA,"Memory at %i with len %i reads: ",ofs,len); + poststr(request,tmpA); + poststr(request,"
"); + + ///res = bekken_hal_flash_read (ofs, buffer,len); + //sprintf(tmpA,"Result %i",res); + // strcat(outbuf,tmpA); + /// strcat(outbuf,"
"); + + nowOfs = ofs; + rem = len; + while(1) { + if(rem > sizeof(buffer)) { + now = sizeof(buffer); + } else { + now = rem; + } +#if PLATFORM_XR809 + //uint32_t flash_read(uint32_t flash, uint32_t addr,void *buf, uint32_t size) + #define FLASH_INDEX_XR809 0 + res = flash_read(FLASH_INDEX_XR809, nowOfs, buffer, now); +#else + res = bekken_hal_flash_read (nowOfs, buffer,now); +#endif + for(i = 0; i < now; i++) { + u8 val = buffer[i]; + if(!hex && isprint(val)) { + sprintf(tmpA,"'%c' ",val); + } else { + sprintf(tmpA,"%02X ",val); + } + poststr(request,tmpA); + } + rem -= now; + nowOfs += now; + if(rem <= 0) { + break; + } + } + + poststr(request,"
"); + } + poststr(request,"
"); poststr(request,"
"); - poststr(request,"
\ -
",ofs); - poststr(request,tmpA); - poststr(request,"
\ - ",len); - poststr(request,tmpA); - poststr(request,"

\ - \ -
"); - - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - - } else if(http_checkUrlBase(urlStr,"cfg_quick")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - poststr(request,"

Quick Config

"); - - if(http_getArg(urlStr,"dev",tmpA,sizeof(tmpA))) { - j = atoi(tmpA); - sprintf(tmpA,"

Set dev %i!

",j); - poststr(request,tmpA); - - g_templates[j].setter(); - } - poststr(request,"
"); - sprintf(tmpA, ""); - poststr(request,"
"); - - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - - - } else if(http_checkUrlBase(urlStr,"cfg_ha")) { - int relayFlags = 0; - int pwmFlags = 0; - int relayCount = 0; - int pwmCount = 0; - const char *baseName; - - baseName = CFG_GetShortDeviceName(); - - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - poststr(request,"

Home Assistant Cfg

"); - poststr(request,"

Paste this to configuration yaml

"); - poststr(request,"
Make sure that you have \"switch:\" keyword only once! Home Assistant doesn't like dup keywords.
"); - poststr(request,"
You can also use \"switch MyDeviceName:\" to avoid keyword duplication!
"); - - poststr(request,""); - - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - - - } else if(http_checkUrlBase(urlStr,"cfg")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - poststr(request,"
"); - poststr(request,"
"); - poststr(request,"
"); - poststr(request,"
"); - poststr(request,"
"); - poststr(request,"
"); - poststr(request,"
"); - poststr(request,"
"); - poststr(request,"
"); - poststr(request,"
"); - -#if PLATFORM_BK7231T | PLATFORM_BK7231N - k = config_get_tableOffsets(BK_PARTITION_NET_PARAM,&i,&j); - sprintf(tmpA,"BK_PARTITION_NET_PARAM: bOk %i, at %i, len %i
",k,i,j); - poststr(request,tmpA); - k = config_get_tableOffsets(BK_PARTITION_RF_FIRMWARE,&i,&j); - sprintf(tmpA,"BK_PARTITION_RF_FIRMWARE: bOk %i, at %i, len %i
",k,i,j); - poststr(request,tmpA); - k = config_get_tableOffsets(BK_PARTITION_OTA,&i,&j); - sprintf(tmpA,"BK_PARTITION_OTA: bOk %i, at %i, len %i
",k,i,j); - poststr(request,tmpA); -#endif - - - poststr(request,"Launch Web Application
"); - - poststr(request,htmlReturnToMenu); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - //} else if(http_checkUrlBase(urlStr,"setWB2SInputs")) { - // http_setup(outbuf, httpMimeTypeHTML); - // poststr(request,htmlHeader); - - // setupAllWB2SPinsAsButtons(); - - // http_setup(outbuf, httpMimeTypeHTML); - // poststr(request,"Set all inputs for dbg ."); - // poststr(request,htmlReturnToMenu); - // HTTP_AddBuildFooter(outbuf); - // poststr(request,htmlEnd); - //} else if(http_checkUrlBase(urlStr,"setAllInputs")) { - // http_setup(outbuf, httpMimeTypeHTML); - // poststr(request,htmlHeader); - // // it breaks UART pins as well, omg! - // for(i = 0; i < GPIO_MAX; i++) { - // PIN_SetPinRoleForPinIndex(i,IOR_Button); - // PIN_SetPinChannelForPinIndex(i,1); - // } - // http_setup(outbuf, httpMimeTypeHTML); - // poststr(request,"Set all inputs for dbg ."); - // poststr(request,htmlReturnToMenu); - // HTTP_AddBuildFooter(outbuf); - // poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"cfg_pins")) { - int iChanged = 0; - int iChangedRequested = 0; - - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - for(i = 0; i < GPIO_MAX; i++) { - sprintf(tmpA, "%i",i); - if(http_getArg(recvbuf,tmpA,tmpB,sizeof(tmpB))) { - int role; - int pr; - - iChangedRequested++; - - role = atoi(tmpB); - - pr = PIN_GetPinRoleForPinIndex(i); - if(pr != role) { - PIN_SetPinRoleForPinIndex(i,role); - iChanged++; - } - } - sprintf(tmpA, "r%i",i); - if(http_getArg(urlStr,tmpA,tmpB,sizeof(tmpB))) { - int rel; - int prevRel; - - iChangedRequested++; - - rel = atoi(tmpB); - - prevRel = PIN_GetPinChannelForPinIndex(i); - if(prevRel != rel) { - PIN_SetPinChannelForPinIndex(i,rel); - iChanged++; - } - } - } - if(iChangedRequested>0) { - PIN_SaveToFlash(); - sprintf(tmpA, "Pins update - %i reqs, %i changed!

",iChangedRequested,iChanged); - poststr(request,tmpA); - } - // strcat(outbuf,""); - poststr(request,"
"); - for( i = 0; i < GPIO_MAX; i++) { - int si, ch; - - si = PIN_GetPinRoleForPinIndex(i); - ch = PIN_GetPinChannelForPinIndex(i); - -#if PLATFORM_XR809 - poststr(request,PIN_GetPinNameAlias(i)); - poststr(request," "); -#else - sprintf(tmpA, "P%i ",i); - poststr(request,tmpA); -#endif - sprintf(tmpA, ""); - if(ch == 0) { - tmpB[0] = 0; - } else { - sprintf(tmpB,"%i",ch); - } - sprintf(tmpA, "",i,tmpB); - poststr(request,tmpA); - poststr(request,"
"); - } - poststr(request,"
"); - - poststr(request,htmlReturnToCfg); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"index")) { - int relayFlags; - int pwmFlags; - - relayFlags = 0; - pwmFlags = 0; - - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,""); - poststr(request,g_header); - if(http_getArg(urlStr,"tgl",tmpA,sizeof(tmpA))) { - j = atoi(tmpA); - sprintf(tmpA,"

Toggled %i!

",j); - poststr(request,tmpA); - CHANNEL_Toggle(j); - } - if(http_getArg(urlStr,"on",tmpA,sizeof(tmpA))) { - j = atoi(tmpA); - sprintf(tmpA,"

Enabled %i!

",j); - poststr(request,tmpA); - CHANNEL_Set(j,255,1); - } - if(http_getArg(urlStr,"off",tmpA,sizeof(tmpA))) { - j = atoi(tmpA); - sprintf(tmpA,"

Disabled %i!

",j); - poststr(request,tmpA); - CHANNEL_Set(j,0,1); - } - if(http_getArg(urlStr,"pwm",tmpA,sizeof(tmpA))) { - int newPWMValue = atoi(tmpA); - http_getArg(urlStr,"pwmIndex",tmpA,sizeof(tmpA)); - j = atoi(tmpA); - sprintf(tmpA,"

Changed pwm %i to %i!

",j,newPWMValue); - poststr(request,tmpA); - CHANNEL_Set(j,newPWMValue,1); - } - - for(i = 0; i < GPIO_MAX; i++) { - int role = PIN_GetPinRoleForPinIndex(i); - int ch = PIN_GetPinChannelForPinIndex(i); - if(role == IOR_Relay || role == IOR_Relay_n || role == IOR_LED || role == IOR_LED_n) { - BIT_SET(relayFlags,ch); - } - if(role == IOR_PWM) { - BIT_SET(pwmFlags,ch); - } - } - for(i = 0; i < CHANNEL_MAX; i++) { - if(BIT_CHECK(relayFlags,i)) { - const char *c; - if(CHANNEL_Check(i)) { - c = "r"; - } else { - c = "g"; - } - poststr(request,"
"); - sprintf(tmpA,"",i); - poststr(request,tmpA); - sprintf(tmpA,"
",c,i); - poststr(request,tmpA); - } - if(BIT_CHECK(pwmFlags,i)) { - int pwmValue; - - pwmValue = CHANNEL_Get(i); - sprintf(tmpA,"
",i); - poststr(request,tmpA); - sprintf(tmpA,"",i,pwmValue); - poststr(request,tmpA); - sprintf(tmpA,"",i); - poststr(request,tmpA); - sprintf(tmpA,"
",i); - poststr(request,tmpA); - - - poststr(request,""); - } - } - // strcat(outbuf,""); - - - if(http_getArg(urlStr,"restart",tmpA,sizeof(tmpA))) { - poststr(request,"
Module will restart soon
"); -#if WINDOWS - -#elif PLATFORM_XR809 - -#else - RESET_ScheduleModuleReset(3); -#endif - } - - poststr(request,"
"); - - poststr(request,"
\ - \ - \ -
"); - - poststr(request,"
"); - - - poststr(request,htmlReturnToMenu); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"ota_exec")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - if(http_getArg(urlStr,"host",tmpA,sizeof(tmpA))) { - sprintf(tmpB,"

OTA requested for %s!

",tmpA); - poststr(request,tmpB); -#if WINDOWS - -#elif PLATFORM_XR809 - //cmd_ota_http_exec(tmpA); - xr809_do_ota_next_frame(tmpA); -#else - otarequest(tmpA); -#endif - } - poststr(request,htmlReturnToMenu); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"ota")) { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,"
\ -
\ -
\ - \ -
"); - poststr(request,htmlReturnToMenu); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } else if(http_checkUrlBase(urlStr,"")) { - // Redirect / to /index page - poststr(request,"HTTP/1.1 302 OK\nLocation: /index\nConnection: close\n\n"); - } else { - http_setup(request, httpMimeTypeHTML); - poststr(request,htmlHeader); - poststr(request,g_header); - poststr(request,"Not found.
"); - poststr(request,htmlReturnToMenu); - HTTP_AddBuildFooter(request); - poststr(request,htmlEnd); - } - - - // force send remaining - poststr(request, NULL); - // nothing more to send - return 0; -} + poststr(request,">
"); + poststr(request,"
\ +
",ofs); + poststr(request,tmpA); + poststr(request,"
\ + ",len); + poststr(request,tmpA); + poststr(request,"

\ + \ + "); + + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + + } else if(http_checkUrlBase(urlStr,"cfg_quick")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + poststr(request,"

Quick Config

"); + + if(http_getArg(urlStr,"dev",tmpA,sizeof(tmpA))) { + j = atoi(tmpA); + sprintf(tmpA,"

Set dev %i!

",j); + poststr(request,tmpA); + + g_templates[j].setter(); + } + poststr(request,"
"); + sprintf(tmpA, ""); + poststr(request,"
"); + + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + + + } else if(http_checkUrlBase(urlStr,"cfg_ha")) { + int relayFlags = 0; + int pwmFlags = 0; + int relayCount = 0; + int pwmCount = 0; + const char *baseName; + + baseName = CFG_GetShortDeviceName(); + + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + poststr(request,"

Home Assistant Cfg

"); + poststr(request,"

Paste this to configuration yaml

"); + poststr(request,"
Make sure that you have \"switch:\" keyword only once! Home Assistant doesn't like dup keywords.
"); + poststr(request,"
You can also use \"switch MyDeviceName:\" to avoid keyword duplication!
"); + + poststr(request,""); + + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + + + } else if(http_checkUrlBase(urlStr,"cfg")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + poststr(request,"
"); + poststr(request,"
"); + poststr(request,"
"); + poststr(request,"
"); + poststr(request,"
"); + poststr(request,"
"); + poststr(request,"
"); + poststr(request,"
"); + poststr(request,"
"); + poststr(request,"
"); + +#if PLATFORM_BK7231T | PLATFORM_BK7231N + k = config_get_tableOffsets(BK_PARTITION_NET_PARAM,&i,&j); + sprintf(tmpA,"BK_PARTITION_NET_PARAM: bOk %i, at %i, len %i
",k,i,j); + poststr(request,tmpA); + k = config_get_tableOffsets(BK_PARTITION_RF_FIRMWARE,&i,&j); + sprintf(tmpA,"BK_PARTITION_RF_FIRMWARE: bOk %i, at %i, len %i
",k,i,j); + poststr(request,tmpA); + k = config_get_tableOffsets(BK_PARTITION_OTA,&i,&j); + sprintf(tmpA,"BK_PARTITION_OTA: bOk %i, at %i, len %i
",k,i,j); + poststr(request,tmpA); +#endif + + + poststr(request,"Launch Web Application
"); + + poststr(request,htmlReturnToMenu); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + //} else if(http_checkUrlBase(urlStr,"setWB2SInputs")) { + // http_setup(outbuf, httpMimeTypeHTML); + // poststr(request,htmlHeader); + + // setupAllWB2SPinsAsButtons(); + + // http_setup(outbuf, httpMimeTypeHTML); + // poststr(request,"Set all inputs for dbg ."); + // poststr(request,htmlReturnToMenu); + // HTTP_AddBuildFooter(outbuf); + // poststr(request,htmlEnd); + //} else if(http_checkUrlBase(urlStr,"setAllInputs")) { + // http_setup(outbuf, httpMimeTypeHTML); + // poststr(request,htmlHeader); + // // it breaks UART pins as well, omg! + // for(i = 0; i < GPIO_MAX; i++) { + // PIN_SetPinRoleForPinIndex(i,IOR_Button); + // PIN_SetPinChannelForPinIndex(i,1); + // } + // http_setup(outbuf, httpMimeTypeHTML); + // poststr(request,"Set all inputs for dbg ."); + // poststr(request,htmlReturnToMenu); + // HTTP_AddBuildFooter(outbuf); + // poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"cfg_pins")) { + int iChanged = 0; + int iChangedRequested = 0; + + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + for(i = 0; i < GPIO_MAX; i++) { + sprintf(tmpA, "%i",i); + if(http_getArg(recvbuf,tmpA,tmpB,sizeof(tmpB))) { + int role; + int pr; + + iChangedRequested++; + + role = atoi(tmpB); + + pr = PIN_GetPinRoleForPinIndex(i); + if(pr != role) { + PIN_SetPinRoleForPinIndex(i,role); + iChanged++; + } + } + sprintf(tmpA, "r%i",i); + if(http_getArg(urlStr,tmpA,tmpB,sizeof(tmpB))) { + int rel; + int prevRel; + + iChangedRequested++; + + rel = atoi(tmpB); + + prevRel = PIN_GetPinChannelForPinIndex(i); + if(prevRel != rel) { + PIN_SetPinChannelForPinIndex(i,rel); + iChanged++; + } + } + } + if(iChangedRequested>0) { + PIN_SaveToFlash(); + sprintf(tmpA, "Pins update - %i reqs, %i changed!

",iChangedRequested,iChanged); + poststr(request,tmpA); + } + // strcat(outbuf,""); + poststr(request,"
"); + for( i = 0; i < GPIO_MAX; i++) { + int si, ch; + + si = PIN_GetPinRoleForPinIndex(i); + ch = PIN_GetPinChannelForPinIndex(i); + +#if PLATFORM_XR809 + poststr(request,PIN_GetPinNameAlias(i)); + poststr(request," "); +#else + sprintf(tmpA, "P%i ",i); + poststr(request,tmpA); +#endif + sprintf(tmpA, ""); + if(ch == 0) { + tmpB[0] = 0; + } else { + sprintf(tmpB,"%i",ch); + } + sprintf(tmpA, "",i,tmpB); + poststr(request,tmpA); + poststr(request,"
"); + } + poststr(request,"
"); + + poststr(request,htmlReturnToCfg); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"index")) { + int relayFlags; + int pwmFlags; + + relayFlags = 0; + pwmFlags = 0; + + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,""); + poststr(request,g_header); + if(http_getArg(urlStr,"tgl",tmpA,sizeof(tmpA))) { + j = atoi(tmpA); + sprintf(tmpA,"

Toggled %i!

",j); + poststr(request,tmpA); + CHANNEL_Toggle(j); + } + if(http_getArg(urlStr,"on",tmpA,sizeof(tmpA))) { + j = atoi(tmpA); + sprintf(tmpA,"

Enabled %i!

",j); + poststr(request,tmpA); + CHANNEL_Set(j,255,1); + } + if(http_getArg(urlStr,"off",tmpA,sizeof(tmpA))) { + j = atoi(tmpA); + sprintf(tmpA,"

Disabled %i!

",j); + poststr(request,tmpA); + CHANNEL_Set(j,0,1); + } + if(http_getArg(urlStr,"pwm",tmpA,sizeof(tmpA))) { + int newPWMValue = atoi(tmpA); + http_getArg(urlStr,"pwmIndex",tmpA,sizeof(tmpA)); + j = atoi(tmpA); + sprintf(tmpA,"

Changed pwm %i to %i!

",j,newPWMValue); + poststr(request,tmpA); + CHANNEL_Set(j,newPWMValue,1); + } + + for(i = 0; i < GPIO_MAX; i++) { + int role = PIN_GetPinRoleForPinIndex(i); + int ch = PIN_GetPinChannelForPinIndex(i); + if(role == IOR_Relay || role == IOR_Relay_n || role == IOR_LED || role == IOR_LED_n) { + BIT_SET(relayFlags,ch); + } + if(role == IOR_PWM) { + BIT_SET(pwmFlags,ch); + } + } + for(i = 0; i < CHANNEL_MAX; i++) { + if(BIT_CHECK(relayFlags,i)) { + const char *c; + if(CHANNEL_Check(i)) { + c = "r"; + } else { + c = "g"; + } + poststr(request,"
"); + sprintf(tmpA,"",i); + poststr(request,tmpA); + sprintf(tmpA,"
",c,i); + poststr(request,tmpA); + } + if(BIT_CHECK(pwmFlags,i)) { + int pwmValue; + + pwmValue = CHANNEL_Get(i); + sprintf(tmpA,"
",i); + poststr(request,tmpA); + sprintf(tmpA,"",i,pwmValue); + poststr(request,tmpA); + sprintf(tmpA,"",i); + poststr(request,tmpA); + sprintf(tmpA,"
",i); + poststr(request,tmpA); + + + poststr(request,""); + } + } + // strcat(outbuf,""); + + + if(http_getArg(urlStr,"restart",tmpA,sizeof(tmpA))) { + poststr(request,"
Module will restart soon
"); +#if WINDOWS + +#elif PLATFORM_XR809 + +#else + RESET_ScheduleModuleReset(3); +#endif + } + + poststr(request,"
"); + + poststr(request,"
\ + \ + \ +
"); + + poststr(request,"
"); + + + poststr(request,htmlReturnToMenu); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"ota_exec")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + if(http_getArg(urlStr,"host",tmpA,sizeof(tmpA))) { + sprintf(tmpB,"

OTA requested for %s!

",tmpA); + poststr(request,tmpB); +#if WINDOWS + +#elif PLATFORM_XR809 + //cmd_ota_http_exec(tmpA); + xr809_do_ota_next_frame(tmpA); +#else + otarequest(tmpA); +#endif + } + poststr(request,htmlReturnToMenu); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"ota")) { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,"
\ +
\ +
\ + \ +
"); + poststr(request,htmlReturnToMenu); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } else if(http_checkUrlBase(urlStr,"")) { + // Redirect / to /index page + poststr(request,"HTTP/1.1 302 OK\nLocation: /index\nConnection: close\n\n"); + } else { + http_setup(request, httpMimeTypeHTML); + poststr(request,htmlHeader); + poststr(request,g_header); + poststr(request,"Not found.
"); + poststr(request,htmlReturnToMenu); + HTTP_AddBuildFooter(request); + poststr(request,htmlEnd); + } + + + // force send remaining + poststr(request, NULL); + // nothing more to send + return 0; +} diff --git a/src/new_builtin_devices.c b/src/new_builtin_devices.c index 201651264..a8989685d 100644 --- a/src/new_builtin_devices.c +++ b/src/new_builtin_devices.c @@ -250,8 +250,10 @@ void Setup_Device_EmaxHome_EDU8774() { PIN_SaveToFlash(); } -// TODO - ELEKTRODA LINK + // QiachipSmartSwitch +// See teardown article here: +// https://www.elektroda.pl/rtvforum/viewtopic.php?t=3874289&highlight= void Setup_Device_BK7231N_CB2S_QiachipSmartSwitch() { @@ -267,6 +269,52 @@ void Setup_Device_BK7231N_CB2S_QiachipSmartSwitch() { PIN_SaveToFlash(); } +void Setup_Device_BK7231T_WB2S_QiachipSmartSwitch() { + PIN_ClearPins(); + // Button + PIN_SetPinRoleForPinIndex(7, IOR_Button); + PIN_SetPinChannelForPinIndex(7, 1); + // Relay + PIN_SetPinRoleForPinIndex(6, IOR_Relay_n); + PIN_SetPinChannelForPinIndex(6, 1); + // Led + PIN_SetPinRoleForPinIndex(10, IOR_LED); + PIN_SetPinChannelForPinIndex(10, 1); + + PIN_SaveToFlash(); +} + + + +// Strigona donation +// Teardown article: https://www.elektroda.pl/rtvforum/viewtopic.php?p=19906670#19906670 +// https://obrazki.elektroda.pl/6606464600_1642467157.jpg +// NOTE: It used to be ESP-based https://templates.blakadder.com/prime_CCWFIO232PK.html +void Setup_Device_BK7231T_Raw_PrimeWiFiSmartOutletsOutdoor_CCWFIO232PK() { + + + + PIN_ClearPins(); + // Relay + PIN_SetPinRoleForPinIndex(6, IOR_Relay); + PIN_SetPinChannelForPinIndex(6, 1); + // Relay + PIN_SetPinRoleForPinIndex(7, IOR_Relay); + PIN_SetPinChannelForPinIndex(7, 2); + // Led + PIN_SetPinRoleForPinIndex(10, IOR_LED); + PIN_SetPinChannelForPinIndex(10, 1); + // Led + PIN_SetPinRoleForPinIndex(26, IOR_LED); + PIN_SetPinChannelForPinIndex(26, 2); + + // Single button + PIN_SetPinRoleForPinIndex(24, IOR_Button); + PIN_SetPinChannelForPinIndex(24, 1); + + + PIN_SaveToFlash(); +} // https://www.tokmanni.fi/alypistorasia-home-connect-ip20-6419860720456 diff --git a/src/new_pins.c b/src/new_pins.c index 7552a9055..c477a9996 100644 --- a/src/new_pins.c +++ b/src/new_pins.c @@ -260,22 +260,31 @@ void RAW_SetPinValue(int index, int iVal){ bk_gpio_output(index, iVal); #endif } -void button_generic_short_press(int index) +void Button_OnShortClick(int index) { - CHANNEL_Toggle(g_pins.channels[index]); - PR_NOTICE("%i key_short_press\r\n", index); + if(g_pins.roles[index] == IOR_Button_ToggleAll || g_pins.roles[index] == IOR_Button_ToggleAll_n) + { + CHANNEL_DoSpecialToggleAll(); + return; + } + CHANNEL_Toggle(g_pins.channels[index]); } -void button_generic_double_press(int index) +void Button_OnDoubleClick(int index) { + PR_NOTICE("%i key_double_press\r\n", index); + if(g_pins.roles[index] == IOR_Button_ToggleAll || g_pins.roles[index] == IOR_Button_ToggleAll_n) + { + CHANNEL_DoSpecialToggleAll(); + return; + } CHANNEL_Toggle(g_pins.channels[index]); if(g_doubleClickCallback!=0) { g_doubleClickCallback(index); } - PR_NOTICE("%i key_double_press\r\n", index); } -void button_generic_long_press_hold(int index) +void Button_OnLongPressHold(int index) { PR_NOTICE("%i key_long_press_hold\r\n", index); } @@ -290,6 +299,13 @@ const char *PIN_GetPinNameAlias(int index) { return "not_implemented_here"; #endif } +bool BTN_ShouldInvert(int index) +{ + if(g_pins.roles[index] == IOR_Button_n || g_pins.roles[index] == IOR_Button_ToggleAll_n) { + return true; + } + return false; +} unsigned char button_generic_get_gpio_value(void *param) { #if WINDOWS @@ -301,13 +317,23 @@ unsigned char button_generic_get_gpio_value(void *param) index = ((pinButton_s*)param) - g_buttons; PIN_XR809_GetPortPinForIndex(index, &xr_port, &xr_pin); - + + if(BTN_ShouldInvert(index)) { + if (HAL_GPIO_ReadPin(xr_port, xr_pin) == GPIO_PIN_LOW) + return 1;//0; + return 0;//1; + } if (HAL_GPIO_ReadPin(xr_port, xr_pin) == GPIO_PIN_LOW) return 0; return 1; #else int index; index = ((pinButton_s*)param) - g_buttons; + + // support inverted button + if(BTN_ShouldInvert(index)) { + return !bk_gpio_input(index); + } return bk_gpio_input(index); #endif } @@ -325,8 +351,75 @@ void NEW_button_init(pinButton_s* handle, uint8_t(*pin_level)(void *self), uint8 handle->button_level = handle->hal_button_Level(handle); handle->active_level = active_level; } +void CHANNEL_SetAll(int iVal) { + int i; + for(i = 0; i < GPIO_MAX; i++) { + switch(g_pins.roles[i]) + { + case IOR_Button: + case IOR_Button_n: + case IOR_Button_ToggleAll: + case IOR_Button_ToggleAll_n: + { + + } + break; + case IOR_LED: + case IOR_LED_n: + case IOR_Relay: + case IOR_Relay_n: + CHANNEL_Set(g_pins.channels[i],iVal,1); + break; + case IOR_PWM: + CHANNEL_Set(g_pins.channels[i],iVal,1); + break; + + default: + break; + } + } +} +bool CHANNEL_IsInUse(int ch) { + int i; + for(i = 0; i < GPIO_MAX; i++){ + if(g_pins.channels[i] == ch) { + switch(g_pins.roles[i]) + { + case IOR_LED: + case IOR_LED_n: + case IOR_Relay: + case IOR_Relay_n: + case IOR_PWM: + return true; + break; + + default: + break; + } + } + } + return false; +} +void CHANNEL_DoSpecialToggleAll() { + int anyEnabled, i; + + anyEnabled = 0; + + for(i = 0; i < CHANNEL_MAX; i++) { + if(CHANNEL_IsInUse(i)==false) + continue; + if(g_channelValues[i] > 0) { + anyEnabled++; + } + } + if(anyEnabled) + CHANNEL_SetAll(0); + else + CHANNEL_SetAll(255); + +} void PIN_SetPinRoleForPinIndex(int index, int role) { //if(index == PIN_UART1_RXD) // return; @@ -340,6 +433,8 @@ void PIN_SetPinRoleForPinIndex(int index, int role) { { case IOR_Button: case IOR_Button_n: + case IOR_Button_ToggleAll: + case IOR_Button_ToggleAll_n: { //pinButton_s *bt = &g_buttons[index]; // TODO: disable button @@ -394,9 +489,10 @@ void PIN_SetPinRoleForPinIndex(int index, int role) { { case IOR_Button: case IOR_Button_n: + case IOR_Button_ToggleAll: + case IOR_Button_ToggleAll_n: { pinButton_s *bt = &g_buttons[index]; - NEW_button_init(bt, button_generic_get_gpio_value, 0); #if WINDOWS #elif PLATFORM_XR809 @@ -415,9 +511,11 @@ void PIN_SetPinRoleForPinIndex(int index, int role) { #else bk_gpio_config_input_pup(index); #endif - /* button_attach(bt, BTN_SINGLE_CLICK, button_generic_short_press); - button_attach(bt, BTN_DOUBLE_CLICK, button_generic_double_press); - button_attach(bt, BTN_LONG_PRESS_HOLD, button_generic_long_press_hold); + // init button after initializing pin role + NEW_button_init(bt, button_generic_get_gpio_value, 0); + /* button_attach(bt, BTN_SINGLE_CLICK, Button_OnShortClick); + button_attach(bt, BTN_DOUBLE_CLICK, Button_OnDoubleClick); + button_attach(bt, BTN_LONG_PRESS_HOLD, Button_OnLongPressHold); button_start(bt);*/ } break; @@ -651,7 +749,7 @@ void PIN_Input_Handler(int pinIndex) handle->repeat++; if(handle->repeat == 2) { EVENT_CB(BTN_DOUBLE_CLICK); // repeat hit - button_generic_double_press(pinIndex); + Button_OnDoubleClick(pinIndex); } EVENT_CB(BTN_PRESS_REPEAT); // repeat hit handle->ticks = 0; @@ -660,7 +758,7 @@ void PIN_Input_Handler(int pinIndex) if(handle->repeat == 1) { handle->event = (uint8_t)BTN_SINGLE_CLICK; EVENT_CB(BTN_SINGLE_CLICK); - button_generic_short_press(pinIndex); + Button_OnShortClick(pinIndex); } else if(handle->repeat == 2) { handle->event = (uint8_t)BTN_DOUBLE_CLICK; } @@ -706,7 +804,8 @@ void PIN_ticks(void *param) { int i; for(i = 0; i < GPIO_MAX; i++) { - if(g_pins.roles[i] == IOR_Button || g_pins.roles[i] == IOR_Button_n) { + if(g_pins.roles[i] == IOR_Button || g_pins.roles[i] == IOR_Button_n + || g_pins.roles[i] == IOR_Button_ToggleAll || g_pins.roles[i] == IOR_Button_ToggleAll_n) { //PR_NOTICE("Test hold %i\r\n",i); PIN_Input_Handler(i); } @@ -746,7 +845,8 @@ void PIN_Init(void) void PIN_set_wifi_led(int value){ int res = -1; - for (int i = 0; i < 32; i++){ + int i; + for ( i = 0; i < 32; i++){ if ((g_pins.roles[i] == IOR_LED_WIFI) || (g_pins.roles[i] == IOR_LED_WIFI_n)){ res = i; break; diff --git a/src/new_pins.h b/src/new_pins.h index 1a6e8760f..066315517 100644 --- a/src/new_pins.h +++ b/src/new_pins.h @@ -18,6 +18,8 @@ enum IORole { IOR_PWM, IOR_LED_WIFI, IOR_LED_WIFI_n, + IOR_Button_ToggleAll, + IOR_Button_ToggleAll_n, IOR_Total_Options, }; @@ -43,6 +45,7 @@ const char *PIN_GetPinNameAlias(int index); void PIN_SetPinRoleForPinIndex(int index, int role); void PIN_SetPinChannelForPinIndex(int index, int ch); void CHANNEL_Toggle(int ch); +void CHANNEL_DoSpecialToggleAll(); bool CHANNEL_Check(int ch); void CHANNEL_SetChangeCallback(void (*cb)(int idx, int iVal)); void PIN_SetGenericDoubleClickCallback(void (*cb)(int pinIndex)); @@ -66,6 +69,8 @@ void Setup_Device_NedisWIFIP130FWT_10A(); void Setup_Device_EmaxHome_EDU8774(); void Setup_Device_TuyaSmartPFW02G(); void Setup_Device_BK7231N_CB2S_QiachipSmartSwitch(); +void Setup_Device_BK7231T_WB2S_QiachipSmartSwitch(); +void Setup_Device_BK7231T_Raw_PrimeWiFiSmartOutletsOutdoor_CCWFIO232PK(); #endif