简介

树莓派作为web服务器,同时通过 GPIO 口控制 LED 灯泡的亮灭,如果要在公网ip进行访问控制,需要借助内网穿透的技术,这里选用 frp 进行穿透。


目录


准备

材料:


树莓派安装Java 11

运行以下命令安装最新的 JDK 版本,目前是 OpenJDK 11 JDK:

sudo apt update
sudo apt install default-jdk

安装完成后,通过命令可以检查 Java 版本进行验证:

java -version

升级WiringPi

WiringPi预装(Pre-installed)在标准的树莓派操作系统Raspbin中。可以使用下面的命令进行安装:

sudo apt-get install wiringpi

如果需要更新WiringPi,可以使用系统更新命令:

sudo apt-get update
sudo apt-get upgrade

WiringPi安装完成后,可以使用下面的命令测试是否安装成功:

sudo gpio -v

另外,可以通过命令打印树莓派引脚分布图

gpio readall

内网穿透配置

腾讯云服务端配置:

[common]
bind_port = 7000

vhost_http_port = 8090
vhost_https_port = 443

[web]
type = http
custom_domains = korilweb.cn

这里设置 http port 为8090,相当于把这个端口和树莓派指定的端口进行绑定。

树莓派客户端配置:

[common]
server_addr = 106.54.131.221
server_port = 7000

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000

[web]
type = http
local_ip = 127.0.0.1
local_port = 9000
custom_domains = korilweb.cn

custom_domains 必须和服务端的一致。


树莓派的web服务器

这里采用 Springboot + pi4j 的方案,Springboot 处理 web 请求,pi4j 处理 GPIO。

引入 pi4j

在 pom.xml 中添加配置

<!-- https://mvnrepository.com/artifact/com.pi4j/pi4j-core -->
<dependency>
    <groupId>com.pi4j</groupId>
    <artifactId>pi4j-core</artifactId>
    <version>1.4</version>
</dependency>

Controller

@RestController
public class HelloController {

    final GpioController gpio = GpioFactory.getInstance();
    final GpioPinDigitalOutput led1 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01);
    @GetMapping(value = "/command/{status}")
    public String test(@PathVariable String status) {
        if (status.equals("open")) {
            led1.high();
            return "led open";
        }
        else if (status.equals("close")) {
            led1.low();
            return "led close";
        }
        return "command error";
    }
}

一个简单的 Controller,将传过来的 Get 请求后的参数,作为控制 LED 灯亮灭的判断条件。

配置文件:

# 应用名称
spring.application.name=raspberry
# 应用服务 WEB 访问端口
server.port=9000

maven 打包好,上传到树莓派。

启动

将 led 灯珠(最好接个电阻,防止电流过大烧掉)正极接到 GPIO_01 上,负极接地。

打开腾讯云8090端口

firewall-cmd --zone=public --add-port=8090/tcp --permanent
firewall-cmd --reload

在腾讯云上,启动 frps

frps -c frps.ini

在树莓派上,启动 frpc

frpc -c frpc.ini

启动树莓派上的Springboot项目

java -jar raspberry-0.0.1-SNAPSHOT.jar

打开postman,发送一个get请求:

http://korilweb.cn:8090/command/open
http://korilweb.cn:8090/command/close

可以看到 LED 根据命令进行开关了。


简单的App

使用手机来控制 LED 是个不错的选择。

这里使用 Android Studio 开发一个简单的 App 应用。目前只有开关的接口,所以需要用到一个 Switch 组件来控制 LED 亮灭。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Switch
        android:id="@+id/switch1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="LED"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

在 MainActivity 中编写对应的逻辑代码

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;

import java.io.IOException;

import okhttp3.OkHttp;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {

    final static OkHttpClient client = new OkHttpClient();
    final static String url = "http://korilweb.cn:8090/command/";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch ledSwitch = findViewById(R.id.switch1);

        ledSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
            if (isChecked) {
                System.out.println("开启");
                new Thread(() -> controlLed("open")).start();
            } else {
                System.out.println("未开启");
                new Thread(() -> controlLed("close")).start();
            }
        });
    }

    /**
     * 发送 get 请求,控制 led 小灯的亮灭
     * @param command 命令参数
     */
    protected void controlLed(String command) {
        Request request = new Request.Builder().url(url + command).build();
        try {
            Response response = client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这里使用 okhttp 来发送请求,需要在 Gradle 中添加:

implementation "com.squareup.okhttp3:okhttp:4.9.0"

最后打包成 apk 即可。


参考

https://shumeipai.nxez.com/2021/01/20/how-to-install-java-jdk-on-raspberry-pi.html

https://blog.csdn.net/qq_33259323/article/details/104441715?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-0&spm=1001.2101.3001.4242

https://zhuanlan.zhihu.com/p/100355512