有什么方法可以让 Arduino 服务器将现有的 .html 文件发送到 Arduino 客户端?

Is there any way to have an Arduino Server send an existing .html file to the Arduino client?

我正在为 Arduino 构建单页应用程序。它在连接 wifi 的平板电脑上以图形方式显示模拟引脚值。

我已经构建了草图,但想清理它。我已经能够将草图上传到我的(Uno Wifi Rev 2)Arduino,初始化 Wifi,并使用平板电脑连接到它。我可以将静态页面 "frame" 发送到平板电脑。 该静态框架能够使用 XMLHttpRequest 对象请求和接收 Arduino 模拟引脚值。

但是发送庞大的静态页面很笨重。教程做的事情,

client.println("<html><body>");
client.println("Hello World!");
client.println("</body></html>");

我试图巧妙地创建一个 FileText.h 头文件:

#define constFileText=
"<html><body>"
"Hello World!"
"</body></html>";

并将其结合:

#include "FileText.h"
client.println(constFileText);

我想做的是创建一个标准 FileText.html:

你好世界!

并用类似的东西处理它:

ifstream hFile ("FileText.html");
while (getline(hFile, strLine))
  client.println(strLine);

这样可以更轻松地编辑 html 文件。它将消除包含所有这些 serial.println 调用的浪费。它还将消除对常量值的最大长度限制。

有什么方法可以向 Arduino 编译器提供文本文件并让 Arduino 服务器将其发送给 Arduino 的客户端?

您可以使用 xxd 工具从您的 HTML 生成包含文件。例如,给一个文件 test.html:

<html><body>
Hello World!
</body></html>

使用 xxd -i test.html > test_html.h 结果 test_html.h 包含:

unsigned char test_html[] = {
  0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e,
  0x0d, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c,
  0x64, 0x21, 0x0d, 0x0a, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c,
  0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e
};
unsigned int test_html_len = 42;

然后您可以在草图中 #include "test_html.h" 并将数组传递给 client.print()。这绕过了字符串大小的限制。不幸的是,您失去了逐行遍历数组的能力,因此如果需要,您必须自己编写一个函数来执行此操作。

xxd is a *nix tool, but there are Windows ports 如果你需要的话。

C++ 有 'raw string literals'。您可以将常量字符串(不转义特殊字符)放入开始和结束 'tag' 之间的源代码中。您可以选择标签作为原始字符串中不存在的内容。在以下示例中,标记为 =====

const char* s1 = R"=====(Hello
"World")=====";

相同
const char* s2 = "Hello\n\"World\"";

这样您就可以将大字符串放入单独的 .h 文件中并包含它们。在 AVR 上使用 PROGMEM 来节省 RAM。

使用@jfowkes 格式(但不是@Juraj)我创建了一个Python 程序。它适用于 Windows 和 Linux。

要使用它,请将所有文本文件(对我来说,.html 和 .js)放在草图的子目录中。然后,从草图文件夹中,运行 python TextEncode.py "SubdirectoryName"。在草图的开头添加 #include "SubdirectoryName.h" 行。该头文件包含一个函数 void SendPage(WiFiClient hClient) ,它将子目录中的文件内容发送到客户端;在适当的时候调用它。

(它确实按字母顺序发送文件,所以我在文件前面加上数字,例如 "F210"。我认为文件是模块。通过有很多这样的模块,我可以通过选择性地禁用模块注释掉代码。我实际上有两个开发模块 [a .js and a .html] 和一个生产模块 [a .js];我在主草图中有一个 SendPage 函数的副本。通过有选择地注释掉代码,我可以选择是否要查看 XMLHttpRequest 函数调用的结果。)

我知道这比其他提议的解决方案要复杂得多,但它有助于开发周期:(1) 在我最喜欢的 IDE 中编辑 html/js 代码 (2) 运行 python 程序(3) 编译草图。

这是我的 TextEncode.py 的内容:

# program to convert text files to file with constant array of ascii code of file characters
# converted file is to be used by Arduino compiler to efficiently send html/js code to Arduino
# Usage:
# 1) place files to be encoded into subfolder, "ClientHtml"
# 2) from console, 'python TextEncode.py "ClientHtml"'.
# 

import os
import sys
import binascii

c_nCharsPerLine = 16
strFolderIn = sys.argv[1]
astrPseudos = []                                        # array of file pseudonyms.  to be used to create inclusive [ClientHtml].h 
if len(sys.argv) > 2:
    strClientHandle = sys.argv[2]
else:
    strClientHandle = "hClient"

for strFileIn in os.listdir(strFolderIn):
# encode each file in subdirectory
# it is easier to re encode every file than it is to check timestamps to re encode only updated files
    strFilePseudo = strFileIn.replace (".", "_")        # to be used in name of encoded file and name of variable with contents of file.
    astrPseudos.append(strFilePseudo)
    strContents = "";                                   # contents read from file itself, in pairs of hex digits

    with open(strFolderIn + "/" + strFileIn, "r") as fileIn:
        nChar = 0;
        for strLineIn in fileIn:
            for chIn in strLineIn:
#               strContents = strContents + chIn.encode("hex") + ","        # works on Linux
                strContents = strContents + hex(ord(chIn)) + ","
                nChar += 1
                if nChar % c_nCharsPerLine == 0:
                    strContents += "\n"
    # truncate trailing \n, if it exists
    if nChar % c_nCharsPerLine == 0:
        strContents = strContents[:-1]
    strContents += "0\n"

    with open (strFilePseudo + ".h", "w") as fileOut:
        fileOut.write("const unsigned char c_" + strFilePseudo + "[] = {\n")
#       fileOut.write("unsigned char c_" + strFilePseudo + "[] = {\n")
        fileOut.write(strContents)
        fileOut.write("};\n")

with open (strFolderIn + ".h", "w") as fileOut:
    fileOut.write("// .h files with encoded files to be included:\n")
    astrPseudos.sort()
    for strFilePseudo in astrPseudos:
        fileOut.write("#include \"" + strFilePseudo + ".h\"\n")
    fileOut.write("/*\n")
    fileOut.write("// Arduino Compiler function to send encoded files to web client:\n")
    fileOut.write("// Comment these out if you don't want to use the functionality\n")
    fileOut.write("void SendPage(WiFiClient " + strClientHandle + ")\n")
    fileOut.write("{\n")
    fileOut.write(" String strData;\n")
    for strFilePseudo in astrPseudos:
        fileOut.write(" strData=c_" + strFilePseudo + ";\n")
        fileOut.write(" " + strClientHandle + ".println(strData);\n")
    fileOut.write("}\n")
    fileOut.write("*/\n")