불로장생 약신경과 피닉스 라이브뷰 구성 요소를 갖춘 사물인터넷 새장🐦
총유기탄소
The basic concept
Setting up a new Elixir Nerves project
Final Word
소개
우리는 크론기술대학에서 새로운 학사학위인 코드 & Context를 받았고 프로젝트 기반의 일을 사랑합니다.여전히 진행 중인 봉쇄 기간에 우리는 캠퍼스의 개방 공간과 어떤 관계를 맺기를 희망한다.
2학기의 학습을 완성하기 위해서, 우리는 프로젝트의 소망이 하나 있다. 바로 원격 브라우저이다.우리뿐만 아니라 미래의 학생이나 완전한 외부인에게 캠퍼스를 탐색하는 선택을 주는 것은 매우 멋있고 우리에게 더욱 긴밀한 관계를 맺는 느낌을 줄 수 있다.
우리는 불로장생 약신경과 봉황 라이브뷰로 사물인터넷 새집을 짓기로 했다.
Elixir는 나에게 다른 프로그래밍 시각을 주었다. 나는 미래의 프로젝트에서 가능한 한 그것을 많이 사용할 것이다.내가 추천한 학습 자원의 링크는 이 문장의 끝에 첨부되어 있다.
너 혼자 해봐.
다음git 저장소에서 코드를 찾을 수 있습니다
Take me to the git repository
기본 개념
Neurs는 Elixir에서 삽입식 시스템을 구축하는 데 사용하기 쉽고 기능이 강한 프레임워크입니다.
나는 확실히 토드 레소드의 강연을 보라고 건의한다. "왜 당신의 다음 하드웨어 프로젝트는 신경으로 구축해야 합니까?"
또한 Phoenix LiveView를 사용하여 다음과 같은 기능을 갖춘 실시간 대시보드를 구축할 수 있습니다.
Neurs는 Elixir에서 삽입식 시스템을 구축하는 데 사용하기 쉽고 기능이 강한 프레임워크입니다.
나는 확실히 토드 레소드의 강연을 보라고 건의한다. "왜 당신의 다음 하드웨어 프로젝트는 신경으로 구축해야 합니까?"
또한 Phoenix LiveView를 사용하여 다음과 같은 기능을 갖춘 실시간 대시보드를 구축할 수 있습니다.
새집 계기판이 운행하고 있다
하드웨어
우리는 프로젝트에서 다음과 같은 하드웨어를 사용할 것이다.
접지
3.3V
5V 전압
GPIO
DHT22형
x
x
사.
서보
x
x
23
발광 다이오드
x
십팔
새로운 불로약 신경 프로젝트를 세우다
불로장생의 약 생태계에 대해 내가 진정으로 좋아하는 것은 네가 필요로 하는 대부분 좋은 기록이 있다는 것이다.
Mac, Linux 또는 Windows에서 개발 환경을 설정하려면 공식 설명서를 참조하십시오.https://hexdocs.pm/nerves/installation.html
우리의 첫 번째 신경 프로젝트를 만들다
우리는 우리의 응용 프로그램에 "poncho 프로젝트"구조를 사용할 것입니다. 따라서 우리는 그것을 몇 개의 작은 응용 프로그램으로 나누고, 이 응용 프로그램들은 모노포에서 생활할 것입니다.
너는 공식 사이트에서 우피 프로젝트의 설정을 찾을 수 있다. https://hexdocs.pm/nerves/user-interfaces.html
안내서를 따를 때 저희 --live
를 잊지 말고 --no-webpack
속성을 생략하십시오.
mix phx.new bird_app_ui --no-ecto --live
SSH를 통한 WiFi 설정 및 업데이트
Neurs는 SSH 설정을 통해 업데이트하는 간단한 방법을 제공하기 때문에 SD카드를 개발 장치에서raspberrypi로 자주 교환할 필요가 없습니다.
WiFi 구성 업데이트
우선 SSID 및 PSK에 환경 변수를 사용할 수 있도록 WiFi 구성을 업데이트합니다.
# bird_app_firmware/config/target.exs
# ...
# Configure the network using vintage_net
# See <https://github.com/nerves-networking/vintage_net> for more information
config :vintage_net,
regulatory_domain: "US",
config: [
{"usb0", %{type: VintageNetDirect}},
{"eth0",
%{
type: VintageNetEthernet,
ipv4: %{method: :dhcp}
}},
{"wlan0",
%{
type: VintageNetWiFi,
vintage_net_wifi: %{
key_mgmt: :wpa_psk,
ssid: System.get_env("NERVES_NETWORK_SSID"),
psk: System.get_env("NERVES_NETWORK_PSK")
},
ipv4: %{method: :dhcp}
}}
]
# ...
환경 변수를 설정하려면 터미널에서 다음 명령을 수행합니다.
export MIX_TARGET=rpi3
export MIX_ENV=dev
export NERVES_NETWORK_SSID=your_wifi_name
export NERVES_NETWORK_PSK=your_wifi_password
SSH 배포 보기
이제 혼합 의존 항목 목록에 nerves_firmware_ssh
패키지를 추가할 수 있습니다
# bird_app_firmware/mix.exs
# ...
defp deps do
[
# Dependencies for all targets
{:nerves_firmware_ssh, "~> 0.3", targets: @all_targets},
{:bird_app_ui, path: "../bird_app_ui"},
{:nerves, "~> 1.6.0", runtime: false},
# ...
]
end
# ...
지금 cd
너의 bird_app_firmware
달리기에 들어간다
mix deps.get
mix firmware
# (Connect the SD card)
mix firmware.burn
지금부터 SD카드를 라즈베리에 삽입한 후 ssh nerves.local
라즈베리 pi에 접근하여 디버깅을 할 수 있고, bird_app_firmware
업데이트를 배치할 수 있습니다
# create new firmware
mix firmware
# upload firmware via ssh
mix upload
Picam - 비디오 스트림 설정
프로젝트에서 Pi NoIR Camera V2 모듈을 사용합니다.
Buy a Pi NoIR Camera V2 - Raspberry Pi
기본 picam 설정
불로장생약 시력
/
피카무
Elixir 라이브러리는 카메라 모듈을 사용하여 라즈베리 원주율에서 MJPEG 영상을 포착하는 데 사용된다.
피카무
Picam은 Elixir 라이브러리로 간단한 API를 제공하여 Linux를 실행하는 Raspberry Pi 장치에서 카메라 모듈을 사용하여 MJPEG 영상을 유동적으로 전송하고 JPEG 영상을 포착하는 데 사용된다.
API가 현재 지원하는 기능:
mix phx.new bird_app_ui --no-ecto --live
# bird_app_firmware/config/target.exs
# ...
# Configure the network using vintage_net
# See <https://github.com/nerves-networking/vintage_net> for more information
config :vintage_net,
regulatory_domain: "US",
config: [
{"usb0", %{type: VintageNetDirect}},
{"eth0",
%{
type: VintageNetEthernet,
ipv4: %{method: :dhcp}
}},
{"wlan0",
%{
type: VintageNetWiFi,
vintage_net_wifi: %{
key_mgmt: :wpa_psk,
ssid: System.get_env("NERVES_NETWORK_SSID"),
psk: System.get_env("NERVES_NETWORK_PSK")
},
ipv4: %{method: :dhcp}
}}
]
# ...
export MIX_TARGET=rpi3
export MIX_ENV=dev
export NERVES_NETWORK_SSID=your_wifi_name
export NERVES_NETWORK_PSK=your_wifi_password
# bird_app_firmware/mix.exs
# ...
defp deps do
[
# Dependencies for all targets
{:nerves_firmware_ssh, "~> 0.3", targets: @all_targets},
{:bird_app_ui, path: "../bird_app_ui"},
{:nerves, "~> 1.6.0", runtime: false},
# ...
]
end
# ...
mix deps.get
mix firmware
# (Connect the SD card)
mix firmware.burn
# create new firmware
mix firmware
# upload firmware via ssh
mix upload
Picam은 Elixir 라이브러리로 간단한 API를 제공하여 Linux를 실행하는 Raspberry Pi 장치에서 카메라 모듈을 사용하여 MJPEG 영상을 유동적으로 전송하고 JPEG 영상을 포착하는 데 사용된다.
API가 현재 지원하는 기능:
요구 사항
요구 사항
메모
호스트 장치
크랜베리 껍질 1, 2, 3, 0/W
0과 0W는 aspecial ribbon cable가 필요합니다.
운영 체제
Linux
상자를 열면 바로 사용할 수 있다.
…
View on GitHub
우선, 우리의bird_ 응용 프로그램 폴더에 새 프로젝트를 만들 것입니다.
실행
mix new bird_app_hardware --sup
주관자와 새로운 혼합 프로젝트를 만들고picam을 의존항 목록에 추가합니다.# bird_app_hardware/mix.exs
# ...
defp deps do
[
{:picam, "~> 0.4.0"}
]
end
# ..
개발 중에 FakeCamera를 사용할 수 있도록 구성을 업데이트bird_app_hardware
합니다.# bird_app_hardware/config/confix.exs
use Mix.Config
config :picam, camera: Picam.FakeCamera
config :logger,
level: :debug,
utc_log: true
config :logger, :console,
level: :debug,
format: "$dateT$time [$level] $message\\n"
bird_app_hardware/lib/bird_app_hardware
및 camera.ex
라는 두 개의 새 파일 만들기# bird_app_hardware/lib/bird_app_hardware/camera.ex
defmodule BirdAppHardware.Camera do
use GenServer
alias BirdAppHardware.Configuration
require Logger
def get_config(), do: GenServer.call(__MODULE__, :get_config)
def set_size(width, height) do
GenServer.call(__MODULE__, {:set_size, width, height})
end
def set_img_effect(effect) do
GenServer.call(__MODULE__, {:set_img_effect, effect})
end
defdelegate next_frame(), to: Picam
def start_link(opts \\\\ []) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end
def init(_opts) do
Logger.info("Configuring camera")
conf = %Configuration{}
Picam.set_size(conf.size.width, conf.size.height)
Picam.set_img_effect(conf.img_effect)
{:ok, conf}
end
def handle_call(:get_config, _from, conf), do: {:reply, conf, conf}
def handle_call({:set_size, width, height}, _from, conf) do
case Picam.set_size(width, height) do
:ok ->
if width > 1280 do
Picam.set_quality(5)
else
Picam.set_quality(15)
end
conf = %{conf | size: %{width: width, height: height}}
{:reply, :ok, conf}
err ->
{:reply, err, conf}
end
end
def handle_call({:set_img_effect, effect}, _from, conf) do
case Picam.set_img_effect(effect) do
:ok ->
conf = %{conf | img_effect: effect}
{:reply, :ok, conf}
err ->
{:reply, err, conf}
end
end
end
# bird_app_hardware/lib/bird_app_hardware/configuration.ex
defmodule BirdAppHardware.Configuration do
defstruct size: %{width: 640, height: 480},
img_effect: :normal
@typedoc @moduledoc
@type t ::
%__MODULE__{
size: dimensions(),
img_effect: img_effect()
}
@type dimensions ::
%{width: non_neg_integer(), height: non_neg_integer()}
@type img_effect ::
:normal
| :sketch
| :oilpaint
end
현재, 우리는 configuration.ex.
에서picam 어린이를 우리의 주관자에게 추가할 수 있다.# bird_app_hardware/lib/bird_app_hardware/application.ex
# ...
def start(_type, _args) do
children = [
# Starts a worker by calling: BirdAppHardware.Worker.start_link(arg)
# {BirdAppHardware.Worker, arg}
Picam.Camera,
BirdAppHardware.Camera
]
# ...
마지막으로 application.ex
항목을 bird_app_hardware
bird_app_firmware
파일 의존 항목에 추가합니다.# bird_app_firmware/mix.exs
# ...
defp deps do
[
# Dependencies for all targets
{:bird_app_hardware, path: "../bird_app_hardware"},
# ...
]
end
# ...
JPG 흐름 구축
우리는picam의 공공 흐름을 원하기 때문에, 우리의
mix.exs
에 포함하고, 케이블 모듈을 만듭니다.# bird_app_ui/lib/bird_app_ui_web/streamer.ex
defmodule BirdAppUi.Streamer do
@moduledoc """
Plug for streaming an image
"""
import Plug.Conn
@behaviour Plug
@boundary "w58EW1cEpjzydSCq"
def init(opts), do: opts
def call(conn, _opts) do
conn
|> put_resp_header("Age", "0")
|> put_resp_header("Cache-Control", "no-cache, private")
|> put_resp_header("Pragma", "no-cache")
|> put_resp_header("Content-Type", "multipart/x-mixed-replace; boundary=#{@boundary}")
|> send_chunked(200)
|> send_pictures
end
defp send_pictures(conn) do
send_picture(conn)
send_pictures(conn)
end
defp send_picture(conn) do
jpg = BirdAppHardware.Camera.next_frame
size = byte_size(jpg)
header = "------#{@boundary}\\r\\nContent-Type: image/jpeg\\r\\nContent-length: #{size}\\r\\n\\r\\n"
footer = "\\r\\n"
with {:ok, conn} <- chunk(conn, header),
{:ok, conn} <- chunk(conn, jpg),
{:ok, conn} <- chunk(conn, footer),
do: conn
end
end
다음 내용을 우리의 bird_app_ui
에 추가합니다.# bird_app_ui/lib/bird_app_ui_web/router.ex
# ...
forward "/video.mjpg", BirdAppUi.Streamer
펌웨어 cd를 router.ex
로 업데이트하고 실행bird_app_firmware
& & mix firmware
.지금 방문할 수 있을 것입니다
mix upload
.그래도 문제가 있어요.60초 후에 표준 설정으로 인해 우리는 시간 초과를 만났다.이 문제를 해결하기 위해서 우리는 nerves.local/video.mjpeg
을 무한대로 바꿔야 한다.# bird_app_firmware/config/target.exs
use Mix.Config
# When we deploy to a device, we use the "prod" configuration:
import_config "../../bird_app_ui/config/config.exs"
import_config "../../bird_app_ui/config/prod.exs"
config :bird_app_ui, BirdAppUiWeb.Endpoint,
# Nerves root filesystem is read-only, so disable the code reloader
code_reloader: false,
http: [
port: 80,
protocol_options: [
idle_timeout: :infinity
]
],
# Use compile-time Mix config instead of runtime environment variables
load_from_system_env: false,
# Start the server since we're running in a release instead of through `mix`
server: true,
url: [host: "nerves.local", port: 80]
#...
지금, 우리는 완벽한 연속 생방송이 우리의picam에서 흘러나오고 있다.단일 이미지에 스냅샷 플러그인 추가
비디오의 단일 이미지에 경로를 쉽게 추가하기 위해
idle_timeout
기능을 이용한 플러그인을 추가할 수 있습니다# bird_app_ui/lib/bird_app_ui_web/snap_plug.ex
defmodule BirdAppUiWeb.SnapPlug do
import Plug.Conn
def init(opts), do: opts
def call(conn, _opts) do
conn
|> put_resp_header("Age", "0")
|> put_resp_header("Cache-Control", "no-cache, private")
|> put_resp_header("Pragma", "no-cache")
|> put_resp_header("Content-Type", "image/jpeg")
|> send_resp(200, BirdAppHardware.Camera.next_frame())
end
end
한 노선next_frame()
을 전달합니다.# bird_app_ui/lib/bird_app_ui_web/router.ex
# ...
forward "/snap.jpg", BirdAppUiWeb.SnapPlug
# ...
온도 및 습도 센서용 LiveView 구성 요소
저는 DHT22를 온도/습도 센서로 사용하여 GPIO 4 인풋 및 다음 6각 패키지에 연결합니다.
회사 명 / dht 회사
Elixir는 DHT11 및 DHT22 센서 읽기 가능
DHT 회사
DHT 11, DHT 22 및 AM2302 온도/습도 센서 드라이브
설치
포트 연결Adafruit Python DHT 라이브러리
pin 읽기를 처리하기 위한 C 소스 코드입니다.
현재 이것은 효과적인 신경 목표만 지원하지만, 미래에는 사용할 수 있을 것이다
GPIO가 있는 불로장생약 환경에서 사용(예를 들어rasbian).
지원되지 않는 플랫폼(예: 호스트, MacOS 등)의 경우 읽기 수는 유효하지만
무작위 생성.def deps() do
{:dht, "~> 0.1"}
end
포트 연결Adafruit Python DHT 라이브러리
pin 읽기를 처리하기 위한 C 소스 코드입니다.
현재 이것은 효과적인 신경 목표만 지원하지만, 미래에는 사용할 수 있을 것이다
GPIO가 있는 불로장생약 환경에서 사용(예를 들어rasbian).
지원되지 않는 플랫폼(예: 호스트, MacOS 등)의 경우 읽기 수는 유효하지만
무작위 생성.
def deps() do {:dht, "~> 0.1"} end
See the datasheets for more info:
활용단어참조
You need to specify the GPIO pin number and sensor type when taking a reading The sensor type can be a string, atom, or integer representation of the target sensor:
iex()> DHT.read(6, :dht22)
{:ok, %{temperature: 22.6, humidity: 50.5}}
iex()> DHT.
…
Add dht to your list of dependencies.
# bird_app_hardware/mix.exs
# ...
defp deps do
[
{:dht, "~> 0.1"}
]
end
# ..
GenServer를 다시 사용할 것입니다. GenServer가 초기화되면 2초 간격으로 /snap.jpg
으로 데이터 조회를 시작하고 원격 이벤트를 사용할 수 있습니다.# bird_app_hardware/lib/bird_app_hardware/dht.ex
defmodule BirdAppHardware.Dht do
use GenServer
require Logger
@dht_pin Application.get_env(:bird_app_hardware, :dht_pin, 4)
def start_link(state \\ []) do
GenServer.start_link(__MODULE__, state, name: __MODULE__)
end
def init(_state) do
Logger.info("Starting DHT Sensor")
DHT.start_polling(@dht_pin, :dht22, 2)
{:ok, %{temperature: "Loading...", humidity: "Loading..."}}
end
def read() do
GenServer.call(__MODULE__, :read)
end
def handle_call(:read, _from, state) do
{:reply, state, state}
end
def handle_cast({:update, measurements}, _state) do
{:noreply,
%{
humidity: floor(measurements.humidity),
temperature: floor(measurements.temperature)
}}
end
def handle_event(_event, measurements, _metadata, _config) do
GenServer.cast(__MODULE__, {:update, measurements})
|> broadcast(:dht_update, %{
humidity: floor(measurements.humidity),
temperature: floor(measurements.temperature)
})
end
def subscribe do
Phoenix.PubSub.subscribe(BirdAppUi.PubSub, "dht")
end
defp broadcast(:ok, event, data) do
Phoenix.PubSub.broadcast(BirdAppUi.PubSub, "dht", {event, data})
{:ok, data}
end
end
# bird_app_ui/lib/bird_app_ui/application.ex
# ...
:telemetry.attach("dht", [:dht, :read], &BirdAppHardware.Dht.handle_event/4, nil)
# ...
이제 LiveComponent를 만듭니다. LiveView에 살고 연결을 맺은 후 바로 이 이벤트에 가입합니다.그런 다음 LiveView는 브로드캐스트를 처리하고 각 LiveComponent에 업데이트를 전송합니다.
# bird_app_ui/lib/bird_app_ui_web/live/components/stats_component.ex
defmodule BirdAppUiWeb.StatsComponent do
use BirdAppUiWeb, :live_component
@impl true
def mount(socket) do
{:ok, socket}
end
@impl true
def update(assigns, socket) do
{:ok, assign(socket, assigns)}
end
@impl true
def render(assigns) do
~L"""
<div class="w-full md:w-1/3 p-3">
<div class="rounded shadow-lg p-2">
<div class="flex flex-row items-center">
<div class="flex-shrink pr-4">
<!-- empty div so bg-colors don't get purged while we load the css class from the @color variable -->
<div class="bg-green-600 bg-blue-600 bg-orange-600 hidden"></div>
<div class="rounded p-3 bg-<%= @color %>-600"><i class="fa <%= @icon %> fa-2x fa-fw fa-inverse"></i></div>
</div>
<div class="flex-1 text-right md:text-center">
<h5 class="font-bold uppercase text-gray-400"><%= @stats_name %></h5>
<h3 class="font-bold text-3xl text-gray-600"><%= @stats %><%= @character %></h3>
</div>
</div>
</div>
</div>
"""
end
end
# bird_app_ui/lib/bird_app_ui_web/live/page_live.ex
# ...
@impl true
def mount(_params, _session, socket) do
if connected?(socket), do: BirdAppHardware.Dht.subscribe()
measurements = BirdAppHardware.Dht.read()
{:ok,
assign(socket,
temperature: measurements.temperature,
humidity: measurements.humidity
)}
end
@impl true
def handle_info({:dht_update, measurements}, socket) do
send_update(BirdAppUiWeb.StatsComponent, id: "humidity", stats: measurements.humidity)
send_update(BirdAppUiWeb.StatsComponent, id: "temperature", stats: measurements.temperature)
{:noreply, socket}
end
# ...
# bird_app_ui/lib/bird_app_ui_web/live/page_live.html.leex
# ...
<%= live_component @socket, BirdAppUiWeb.StatsComponent, id: "temperature", stats: @temperature, stats_name: "Temperature", color: "orange", icon: "fa-thermometer-half", character: "°C" %>
<%= live_component @socket, BirdAppUiWeb.StatsComponent, id: "humidity", stats: @humidity, stats_name: "Humidity", color: "blue", icon: "fa-tint", character: "%" %>
# ...
이 프로젝트에서 Tailwind-CSS를 사용했음을 알 수 있습니다.elixir 프로젝트에서 Tailwind CSS를 설정하는 방법에 관심이 있으시면 https://andrich.me/learn-elixir-and-phoenix-add-tailwind-css텔레그램 채팅으로 스냅샷 보내기
만약 네가 공교롭게도 새 한 마리가 시냇물 속에서 생활하는 것을 보았다면, 이 순간을 붙잡는 것이 가장 좋다.응용 프로그램에서 간단한 전신 로봇을 어떻게 실현하는지 보여 드리겠습니다.
나는nadiatelegrambothex패키지를 사용할 것이다.
활용단어참조 / 나디아
Elixir로 작성된 텔레 로봇 API 패키지
나디아
Elixir(document로 작성된 텔레 로봇 API 패키지
설치
Nadia를 의존 항목DHT.start_polling(4, :dht22, 2)
에 추가합니다.def deps do
[{:nadia, "~> 0.7.0"}]
end
and run $ mix deps.get
.
프로비저닝
In config/config.exs
, add your Telegram Bot token like this
config :nadia
token: "bot token"
You can also add an optional recv_timeout in seconds (defaults to 5s).
config :nadia,
recv_timeout: 10
You can also add a proxy support.
config :nadia,
proxy: "http://proxy_host:proxy_port", # or {:socks5, 'proxy_host', proxy_port}
proxy_auth: {"user", "password"},
ssl: [versions: [:'tlsv1.2']]
You can also configure the the base url for the api if you need to for some reason.
config :nadia,
# Telegram API. Default: https://api.telegram.org/bot
base_url: "http://my-own-endpoint.com/whatever/",
# Telegram Graph API. Default: https://api.telegra.ph
graph_base_url: "http://my-own-endpoint.com/whatever/"
Environment…
First install the necessary dependencies
# bird_app_ui/mix.exs
# ...
{:nadia, "~> 0.7.0"}
# ...
config/config에서exs, 이렇게 전신 로봇 영패 추가# bird_app_ui/config/config.exs
# ...
config :nadia,
token: System.get_env("TELEGRAM_BOT_TOKEN"),
chat_id: System.get_env("TELEGRAM_CHAT_ID")
# ...
이제 새 LiveComponent를 만듭니다.# bird_app_ui/lib/bird_app_ui_web/live/telegram_snap_component.ex
defmodule BirdAppUiWeb.TelegramSnapComponent do
use BirdAppUiWeb, :live_component
alias BirdAppHardware.Camera
@chat_id Application.get_env(:nadia, :chat_id)
@impl true
def mount(socket) do
{:ok, socket}
end
@impl true
def render(assigns) do
~L"""
<button class="w-full font-bold bg-white hover:bg-gray-100 text-gray-800 py-2 px-4 border border-gray-400 rounded shadow my-2" phx-click="snap" phx-target="<%= @myself %>">
Snap
</button>
"""
end
@impl true
def handle_event("snap", _, socket) do
File.write!("/tmp/snap.jpg", Camera.next_frame())
Nadia.send_photo(@chat_id, "/tmp/snap.jpg")
{:noreply, socket}
end
end
# bird_app_ui/lib/bird_app_ui_web/live/page_live.html.leex
# ...
<%= live_component @socket, BirdAppUiWeb.TeleGramSnapComponent, id: "telegram-snap" %>
# ...
단추를 눌렀을 때, 구성 요소는 mix.exs
이벤트를 자신에게 보냅니다. 우리는 먼저 임시 snap
파일에 snap.jpg
의 내용을 포함하고, 최종적으로 그것을 전보로 보낼 수 있습니다.마지막 한마디
솔직히 말하면, 나는 Elixir로 물건을 개발하고 구축하는 데 많은 즐거움을 가지고 있으며, 미래에는 더 많이 할 것이다.
내 명세서에는 실시간 조류 검출 같은 임무가 있다.우리는 또한 모든 내용을 아래의 물리적 새집에 실현하고 3d로 추가 자산, 예를 들어picam 브래킷과 음식 용기를 인쇄해야 한다.
나는 모든 구성 요소를 상세하게 소개하지 않았다.응용 프로그램 개발에 관심이 있다면 git repository 을 보고 사용해 보세요!
불로장생약, 신경, 봉황대 덕분에💫
나의 학습 자원
Reference
이 문제에 관하여(불로장생 약신경과 피닉스 라이브뷰 구성 요소를 갖춘 사물인터넷 새장🐦), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/dasky/an-iot-birdhouse-with-elixir-nerves-phoenix-liveview-components-5cb2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)