Last active
February 22, 2025 03:49
-
-
Save robinchew/94d1b134a4b2a026d1bdfae3551c5520 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(gas_sensor_atomvm). | |
-export([ | |
start/0, | |
init_handler/2, | |
handle_http_req/2, | |
handle_ws_init/3, | |
handle_ws_message/2, | |
poll_server1/3 | |
]). | |
-record(state, { | |
path_suffix, | |
handler_config | |
}). | |
-include_lib("config.hrl"). | |
-define(COMMON_HEADERS, #{"Content-Type" => "text/plain", "Access-Control-Allow-Origin" => "*"}). | |
poll_server1(SensorDataServerPid, ProcPrinter, {Socket, Pid}) -> | |
receive | |
{remove_client, Socket} -> | |
Pid ! stop_poll_server_client, | |
poll_server1(SensorDataServerPid, ProcPrinter, no_client); | |
UnexpectedMessage -> | |
io:format("poll_server received an unexpected message ~p~n", [UnexpectedMessage]) | |
end; | |
poll_server1(SensorDataServerPid, ProcPrinter, no_client) -> | |
PollRate = 3000, | |
receive | |
{new_client, NewSocket} -> | |
NewEventPid = spawn(fun Repeat() -> | |
spawn_link(fun() -> | |
Data1 = <<"2,2025-02-21T15:32:31,22,46,18,23,5,2023,0,28702,24461,65528,11692,8758,1574,6,6,6,0,29,6,56881,0 | |
1,2025-02-21T15:32:31,16,54,1,23,5,2023,0,29931,21314,35152,30298,2981,2101,510,2872,45,4171,155,16,46034,1 | |
3,2025-02-21T15:32:32,13,38,17,23,5,2023,0,30564,19755,33257,13510,2983,2984,473,2506,300,5014,297,16,47230,1">>, | |
httpd_ws_handler:send(NewSocket, Data1) | |
end), | |
receive | |
stop_poll_server_client -> end_process | |
after PollRate -> Repeat() | |
end | |
end), | |
poll_server1(SensorDataServerPid, ProcPrinter, {NewSocket, NewEventPid}); | |
_ -> blah | |
end. | |
start() -> | |
ssl:start(), | |
Self = self(), | |
Config = [ | |
{sta, [ | |
{ssid, ?WIFI_SSID}, | |
{psk, ?WIFI_PASSWORD}, | |
{connected, fun() -> Self ! connected end}, | |
{got_ip, fun(IpInfo) -> Self ! {ok, IpInfo} end}, | |
{disconnected, fun() -> Self ! disconnected end} | |
]} | |
], | |
case network:start(Config) of | |
{ok, Pid} -> | |
io:format("Network Started ~p~n", [Pid]), | |
wait_for_message([]); | |
Error -> | |
io:format("An error occurred starting network: ~p~n", [Error]) | |
end. | |
wait_for_message(_Messages) -> | |
continue = (fun | |
Loop(#{ip_acquired := _}) -> | |
continue; | |
Loop(Map) -> | |
Loop(receive | |
connected -> | |
Map; | |
{ok, IpInfo} -> | |
io:format("Acquired IP address: ~p~n", [IpInfo]), | |
Map#{ip_acquired => IpInfo}; | |
ntp_synced -> | |
io:format("NTP Synced~n"), | |
Map#{ntp_synced => true}; | |
disconnected -> | |
Map | |
after 15000 -> | |
Map | |
end) | |
end)(#{}), | |
spawn_link(fun Loop() -> | |
Pids = erlang:processes(), | |
io:format("FREE HEAP SIZE: ~p (~p processes)~n", [erlang:system_info(esp32_free_heap_size), length(Pids)]), | |
% lists:foreach( | |
% fun(Pid) -> | |
% {_, Mem, _} = just_log_pid(Pid), | |
% io:format("~p ~p~n", [Pid, Mem]) | |
% end, | |
% Pids), | |
timer:sleep(5000), | |
Loop() | |
end), | |
PollServer = spawn_link(fun() -> | |
io:format("poll_server ~p~n", [self()]), | |
poll_server1(null, null, no_client) | |
end), | |
httpd:start_link(80, [ | |
{[<<"events">>], #{ | |
handler => httpd_ws_handler, | |
handler_config => #{ | |
module => ?MODULE, | |
args => [ | |
{poll_server, PollServer} | |
] | |
} | |
}}, | |
{[], #{ | |
handler => ?MODULE | |
}} | |
]), | |
(fun InfiniteLoop() -> | |
receive | |
Msg -> | |
io:format("Got ~p. But still blocking forever.~n", [Msg]), | |
InfiniteLoop() | |
end | |
end)(). | |
init_handler(PathSuffix, HandlerConfig) -> | |
{ok, #state{ | |
path_suffix = PathSuffix, | |
handler_config = HandlerConfig | |
}}. | |
handle_http_req(_Request, _State) -> | |
{close, ?COMMON_HEADERS#{"Content-Type" => "text/html"}, <<" | |
<script> | |
const eventSource = new window.WebSocket('/events'); | |
eventSource.onopen = (e) => { | |
console.log('ws open', e); | |
}; | |
eventSource.onmessage = ({ data }) => { | |
if (data === 'close') { | |
eventSource.close(); | |
return; | |
} | |
if (data === 'pong') { | |
return; | |
} | |
}; | |
setInterval( | |
() => { | |
eventSource.send('ping'); | |
}, | |
10000); | |
</script> | |
">>}. | |
% WEBSOCKET | |
handle_ws_init(WebSocket, _Path = "", Conn) -> | |
PollServer = proplists:get_value(poll_server, Conn), | |
WsInnerSpawn = spawn_link(fun() -> | |
io:format("WebSocket init PID ~p -> ~p~n", [WebSocket, self()]), | |
timer:sleep(2000), | |
PollServer ! {new_client, WebSocket} | |
end), | |
{ok, {inner_spawn, WsInnerSpawn}}. | |
handle_ws_message(<<"ping">>, State) -> | |
{reply, <<"pong">>, State}; | |
handle_ws_message(Message, State) -> | |
io:format("Received message from web socket. Message: ~p~n", [Message]), | |
{noreply, State}. |
Remember to set in config.hrl
:
-define(WIFI_SSID, "MY_SSID").
-define(WIFI_PASSWORD, "mypassword123").
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output of above code here: https://gist.github.com/robinchew/14e3d6f0c4bd4410c5eb30c0b6156b08