Skip to content

Commit d901141

Browse files
authored
feat: Add native esp-idf template (#42)
Tested with generating a Vue3 app for esp32, using esp-idf v5.3.2 This is perfectly functional, but there's always room for improvement. Published in the hope it may be useful for others. Note: no examples for esp-idf. Not sure where best to put them. mini example ``` #include <esp_http_server.h> #include "your_generated_file.h" void start_http_server(void) { httpd_handle_t httpd; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.max_uri_handlers = SVELTEESP32_COUNT + xxx; LOGI("Starting server on port: '%d'", config.server_port); ESP_ERROR_CHECK(httpd_start(&httpd, &config)); initSvelteStaticFiles(httpd); // any other handlers you need.... } ``` Tested with and without etag, and with and without gzip. Signed-off-by: Karl Palsson <[email protected]>
1 parent 4b6ef34 commit d901141

File tree

4 files changed

+210
-4
lines changed

4 files changed

+210
-4
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ npx svelteesp32 -e psychic2 -s ../svelteapp/dist -o ../esp32project/svelteesp32.
4747

4848
// for ESPAsyncWebServer
4949
npx svelteesp32 -e async -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true
50+
51+
// for native esp-idf
52+
npx svelteesp32 -e espidf -s ../svelteapp/dist -o ../esp32project/svelteesp32.h --etag=true
5053
```
5154

5255
During the **translation process**, the processed file details are visible, and at the end, the result shows the ESP's memory allocation (gzip size)

src/commandLine.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { existsSync, statSync } from 'node:fs';
33
import { parse } from 'ts-command-line-args';
44

55
interface ICopyFilesArguments {
6-
engine: 'psychic' | 'psychic2' | 'async';
6+
engine: 'psychic' | 'psychic2' | 'async' | 'espidf';
77
sourcepath: string;
88
outputfile: string;
99
espmethod: string;
@@ -23,6 +23,7 @@ export const cmdLine = parse<ICopyFilesArguments>(
2323
if (value === 'psychic') return 'psychic';
2424
if (value === 'psychic2') return 'psychic2';
2525
if (value === 'async') return 'async';
26+
if (value === 'espidf') return 'espidf';
2627
throw new Error(`Invalid engine: ${value}`);
2728
},
2829
alias: 'e',

src/cppCode.ts

+18-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { compile as handlebarsCompile, HelperOptions } from 'handlebars';
22

33
import { cmdLine } from './commandLine';
44

5+
import { espidfTemplate } from './template_espidf';
6+
57
export type CppCodeSource = {
68
filename: string;
79
dataname: string;
@@ -577,11 +579,24 @@ void {{methodName}}(AsyncWebServer * server) {
577579
{{/each}}
578580
}`;
579581

582+
583+
const getTemplate = (engine: string): string => {
584+
switch (engine) {
585+
case 'psychic':
586+
return psychicTemplate;
587+
case 'psychic2':
588+
return psychic2Template;
589+
case 'espidf':
590+
return espidfTemplate;
591+
default:
592+
return asyncTemplate;
593+
}
594+
}
595+
596+
580597
let switchValue: string;
581598
export const getCppCode = (sources: CppCodeSources, filesByExtension: ExtensionGroups): string =>
582-
handlebarsCompile(
583-
cmdLine.engine === 'psychic' ? psychicTemplate : cmdLine.engine === 'psychic2' ? psychic2Template : asyncTemplate
584-
)(
599+
handlebarsCompile(getTemplate(cmdLine.engine))(
585600
{
586601
commandLine: process.argv.slice(2).join(' '),
587602
now: `${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`,

src/template_espidf.ts

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
export const espidfTemplate = `
2+
//engine: espidf
3+
//cmdline: {{{commandLine}}}
4+
{{#if created }}
5+
//created: {{now}}
6+
{{/if}}
7+
//
8+
9+
{{#switch etag}}
10+
{{#case "true"}}
11+
#ifdef {{definePrefix}}_ENABLE_ETAG
12+
#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched ON
13+
#endif
14+
{{/case}}
15+
{{#case "false"}}
16+
#ifdef {{definePrefix}}_ENABLE_ETAG
17+
#warning {{definePrefix}}_ENABLE_ETAG has no effect because it is permanently switched OFF
18+
#endif
19+
{{/case}}
20+
{{/switch}}
21+
22+
{{#switch gzip}}
23+
{{#case "true"}}
24+
#ifdef {{definePrefix}}_ENABLE_GZIP
25+
#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched ON
26+
#endif
27+
{{/case}}
28+
{{#case "false"}}
29+
#ifdef {{definePrefix}}_ENABLE_GZIP
30+
#warning {{definePrefix}}_ENABLE_GZIP has no effect because it is permanently switched OFF
31+
#endif
32+
{{/case}}
33+
{{/switch}}
34+
35+
//
36+
{{#if version }}
37+
#define {{definePrefix}}_VERSION "{{version}}"
38+
{{/if}}
39+
#define {{definePrefix}}_COUNT {{fileCount}}
40+
#define {{definePrefix}}_SIZE {{fileSize}}
41+
#define {{definePrefix}}_SIZE_GZIP {{fileGzipSize}}
42+
43+
//
44+
{{#each sources}}
45+
#define {{../definePrefix}}_FILE_{{this.datanameUpperCase}}
46+
{{/each}}
47+
48+
//
49+
{{#each filesByExtension}}
50+
#define {{../definePrefix}}_{{this.extension}}_FILES {{this.count}}
51+
{{/each}}
52+
53+
#include <stdint.h>
54+
#include <esp_err.h>
55+
#include <esp_http_server.h>
56+
57+
//
58+
{{#switch gzip}}
59+
{{#case "true"}}
60+
{{#each sources}}
61+
const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
62+
{{/each}}
63+
{{/case}}
64+
{{#case "false"}}
65+
{{#each sources}}
66+
const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
67+
{{/each}}
68+
{{/case}}
69+
{{#case "compiler"}}
70+
#ifdef {{definePrefix}}_ENABLE_GZIP
71+
{{#each sources}}
72+
const char datagzip_{{this.dataname}}[{{this.lengthGzip}}] = { {{this.bytesGzip}} };
73+
{{/each}}
74+
#else
75+
{{#each sources}}
76+
const char data_{{this.dataname}}[{{this.length}}] = { {{this.bytes}} };
77+
{{/each}}
78+
#endif
79+
{{/case}}
80+
{{/switch}}
81+
82+
//
83+
{{#switch etag}}
84+
{{#case "true"}}
85+
{{#each sources}}
86+
const char * etag_{{this.dataname}} = "{{this.md5}}";
87+
{{/each}}
88+
{{/case}}
89+
{{#case "false"}}
90+
{{/case}}
91+
{{#case "compiler"}}
92+
#ifdef {{definePrefix}}_ENABLE_ETAG
93+
{{#each sources}}
94+
const char * etag_{{this.dataname}} = "{{this.md5}}";
95+
{{/each}}
96+
#endif
97+
{{/case}}
98+
{{/switch}}
99+
100+
{{#each sources}}
101+
102+
static esp_err_t file_handler_{{this.datanameUpperCase}} (httpd_req_t *req)
103+
{
104+
httpd_resp_set_type(req, "{{this.mime}}");
105+
{{#switch ../gzip}}
106+
{{#case "true"}}
107+
{{#if this.isGzip}}
108+
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
109+
{{/if}}
110+
{{/case}}
111+
{{#case "compiler"}}
112+
{{#if this.isGzip}}
113+
#ifdef {{../definePrefix}}_ENABLE_GZIP
114+
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
115+
#endif
116+
{{/if}}
117+
{{/case}}
118+
{{/switch}}
119+
120+
{{#switch ../etag}}
121+
{{#case "true"}}
122+
{{#../cacheTime}}
123+
httpd_resp_set_hdr(req, "Cache-Control", "max-age={{value}}");
124+
{{/../cacheTime}}
125+
{{^../cacheTime}}
126+
httpd_resp_set_hdr(req, "Cache-Control", "no-cache");
127+
{{/../cacheTime}}
128+
httpd_resp_set_hdr(req, "ETag", etag_{{this.dataname}});
129+
{{/case}}
130+
{{#case "compiler"}}
131+
#ifdef {{../definePrefix}}_ENABLE_ETAG
132+
{{#../cacheTime}}
133+
httpd_resp_set_hdr(req, "Cache-Control", "max-age={{value}}");
134+
{{/../cacheTime}}
135+
{{^../cacheTime}}
136+
httpd_resp_set_hdr(req, "Cache-Control", "no-cache");
137+
{{/../cacheTime}}
138+
httpd_resp_set_hdr(req, "ETag", etag_{{this.dataname}});
139+
#endif
140+
{{/case}}
141+
{{/switch}}
142+
143+
{{#switch ../gzip}}
144+
{{#case "true"}}
145+
httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});
146+
{{/case}}
147+
{{#case "false"}}
148+
httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});
149+
{{/case}}
150+
{{#case "compiler"}}
151+
#ifdef {{../definePrefix}}_ENABLE_GZIP
152+
httpd_resp_send(req, datagzip_{{this.dataname}}, {{this.lengthGzip}});
153+
#else
154+
httpd_resp_send(req, data_{{this.dataname}}, {{this.length}});
155+
#endif
156+
{{/case}}
157+
{{/switch}}
158+
return ESP_OK;
159+
}
160+
161+
{{#if this.isDefault}}
162+
static const httpd_uri_t route_def_{{this.datanameUpperCase}} = {
163+
.uri = "/",
164+
.method = HTTP_GET,
165+
.handler = file_handler_{{this.datanameUpperCase}},
166+
};
167+
{{/if}}
168+
169+
static const httpd_uri_t route_{{this.datanameUpperCase}} = {
170+
.uri = "/{{this.filename}}",
171+
.method = HTTP_GET,
172+
.handler = file_handler_{{this.datanameUpperCase}},
173+
};
174+
175+
{{/each}}
176+
177+
178+
179+
static inline void {{methodName}}(httpd_handle_t server) {
180+
{{#each sources}}
181+
{{#if this.isDefault}}
182+
httpd_register_uri_handler(server, &route_def_{{this.datanameUpperCase}});
183+
{{/if}}
184+
httpd_register_uri_handler(server, &route_{{this.datanameUpperCase}});
185+
{{/each}}
186+
187+
}`;

0 commit comments

Comments
 (0)