

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 设置您的 Raspberry Pi 和含水量传感器
<a name="iot-moisture-raspi-setup"></a>



将 Micro SD 卡插入 Raspberry Pi 中，连接显示器、键盘、鼠标以及以太网电缆（如果您未使用 Wi-Fi）。先不要连接电源线。

将 JST 跳线连接到含水量传感器。跳线的另一端有四根电线：
+ 绿色：I2C SCL
+ 白色：I2C SDA
+ 红色：电源 (3.5 V)
+ 黑色：接地

握住 Raspberry Pi（以太网插孔位于右侧）。以该方向握持时，可看到顶部有两排 GPIO 引脚。按照以下顺序将含水量传感器的电线连接到下排引脚。从最左侧的引脚开始，连接红色（电源）、白色（SDA）和绿色（SCL）电线。跳过一个引脚，然后连接黑色（接地）电线。有关更多信息，请参阅 [Python 计算机接线](https://learn.adafruit.com/adafruit-stemma-soil-sensor-i2c-capacitive-moisture-sensor/python-circuitpython-test)。

将电源线连接到 Raspberry Pi，然后将另一端插入墙壁插座以将其打开。

**配置您的 Raspberry Pi**

1. 在**欢迎使用 Raspberry Pi**页面上，选择**下一步**。

1. 选择您的国家/地区、语言、时区和键盘布局。选择**下一步**。

1. 输入 Raspberry Pi 的密码，然后选择**下一步**。

1. 选择您的 Wi-Fi 网络，然后选择**下一步**。如果不使用 Wi-Fi 网络，则选择**跳过**。

1. 选择**下一步**检查软件更新。完成更新后，选择**重启**以重启您的 Raspberry Pi。

在 Raspberry Pi 启动后，启用 I2C 接口。

1. 在 Raspbian 桌面的左上角，单击 Raspberry 图标，选择**首选项**，然后选择 **Raspberry Pi 配置**。

1. 在**接口**选项卡上，对于 **I2C**，选择**启用**。

1. 选择**确定**。

Adafruit STEMMA 湿度传感器的库是为之编写的。 CircuitPython要在 Raspberry Pi 上运行它们，需要安装最新版本的 Python 3。

1. 在命令提示符中运行以下命令来更新 Raspberry Pi 软件：

   `sudo apt-get update`

   `sudo apt-get upgrade`

1. 运行以下命令，更新您的 Python 3 安装：

   `sudo pip3 install --upgrade setuptools`

1. 运行以下命令，安装 Raspberry Pi GPIO 库：

   `pip3 install RPI.GPIO`

1. 运行以下命令，安装 Adafruit Blinka 库：

   `pip3 install adafruit-blinka`

   有关更多信息，请参阅[在 Raspberry Pi 上安装 CircuitPython 库](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/installing-circuitpython-on-raspberry-pi)。

1. 运行以下命令，安装 Adafruit Seesaw 库：

   `sudo pip3 install adafruit-circuitpython-seesaw`

1. 运行以下命令安装适用于 Python 的 Amazon IoT 设备 SDK：

   `pip3 install AWSIoTPythonSDK`

Raspberry Pi 现已具备所有必需的库。创建一个名为 **moistureSensor.py** 的文件，并将以下 Python 代码复制到该文件中：

```
from adafruit_seesaw.seesaw import Seesaw
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient
from board import SCL, SDA

import logging
import time
import json
import argparse
import busio

# Shadow JSON schema:
#
# {
#   "state": {
#       "desired":{
#           "moisture":<INT VALUE>,
#           "temp":<INT VALUE>            
#       }
#   }
# }

# Function called when a shadow is updated
def customShadowCallback_Update(payload, responseStatus, token):

    # Display status and data from update request
    if responseStatus == "timeout":
        print("Update request " + token + " time out!")

    if responseStatus == "accepted":
        payloadDict = json.loads(payload)
        print("~~~~~~~~~~~~~~~~~~~~~~~")
        print("Update request with token: " + token + " accepted!")
        print("moisture: " + str(payloadDict["state"]["reported"]["moisture"]))
        print("temperature: " + str(payloadDict["state"]["reported"]["temp"]))
        print("~~~~~~~~~~~~~~~~~~~~~~~\n\n")

    if responseStatus == "rejected":
        print("Update request " + token + " rejected!")

# Function called when a shadow is deleted
def customShadowCallback_Delete(payload, responseStatus, token):

     # Display status and data from delete request
    if responseStatus == "timeout":
        print("Delete request " + token + " time out!")

    if responseStatus == "accepted":
        print("~~~~~~~~~~~~~~~~~~~~~~~")
        print("Delete request with token: " + token + " accepted!")
        print("~~~~~~~~~~~~~~~~~~~~~~~\n\n")

    if responseStatus == "rejected":
        print("Delete request " + token + " rejected!")


# Read in command-line parameters
def parseArgs():

    parser = argparse.ArgumentParser()
    parser.add_argument("-e", "--endpoint", action="store", required=True, dest="host", help="Your device data endpoint")
    parser.add_argument("-r", "--rootCA", action="store", required=True, dest="rootCAPath", help="Root CA file path")
    parser.add_argument("-c", "--cert", action="store", dest="certificatePath", help="Certificate file path")
    parser.add_argument("-k", "--key", action="store", dest="privateKeyPath", help="Private key file path")
    parser.add_argument("-p", "--port", action="store", dest="port", type=int, help="Port number override")
    parser.add_argument("-n", "--thingName", action="store", dest="thingName", default="Bot", help="Targeted thing name")
    parser.add_argument("-id", "--clientId", action="store", dest="clientId", default="basicShadowUpdater", help="Targeted client id")

    args = parser.parse_args()
    return args


# Configure logging
# AWSIoTMQTTShadowClient writes data to the log
def configureLogging():

    logger = logging.getLogger("AWSIoTPythonSDK.core")
    logger.setLevel(logging.DEBUG)
    streamHandler = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    streamHandler.setFormatter(formatter)
    logger.addHandler(streamHandler)


# Parse command line arguments
args = parseArgs()

if not args.certificatePath or not args.privateKeyPath:
    parser.error("Missing credentials for authentication.")
    exit(2)

# If no --port argument is passed, default to 8883
if not args.port: 
    args.port = 8883


# Init AWSIoTMQTTShadowClient
myAWSIoTMQTTShadowClient = None
myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient(args.clientId)
myAWSIoTMQTTShadowClient.configureEndpoint(args.host, args.port)
myAWSIoTMQTTShadowClient.configureCredentials(args.rootCAPath, args.privateKeyPath, args.certificatePath)

# AWSIoTMQTTShadowClient connection configuration
myAWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10) # 10 sec
myAWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5) # 5 sec

# Initialize Raspberry Pi's I2C interface
i2c_bus = busio.I2C(SCL, SDA)

# Intialize SeeSaw, Adafruit's Circuit Python library
ss = Seesaw(i2c_bus, addr=0x36)

# Connect to Amazon IoT
myAWSIoTMQTTShadowClient.connect()

# Create a device shadow handler, use this to update and delete shadow document
deviceShadowHandler = myAWSIoTMQTTShadowClient.createShadowHandlerWithName(args.thingName, True)

# Delete current shadow JSON doc
deviceShadowHandler.shadowDelete(customShadowCallback_Delete, 5)

# Read data from moisture sensor and update shadow
while True:

    # read moisture level through capacitive touch pad
    moistureLevel = ss.moisture_read()

    # read temperature from the temperature sensor
    temp = ss.get_temp()

    # Display moisture and temp readings
    print("Moisture Level: {}".format(moistureLevel))
    print("Temperature: {}".format(temp))
    
    # Create message payload
    payload = {"state":{"reported":{"moisture":str(moistureLevel),"temp":str(temp)}}}

    # Update shadow
    deviceShadowHandler.shadowUpdate(json.dumps(payload), customShadowCallback_Update, 5)
    time.sleep(1)
```

将文件保存到您可以找到的位置。在命令行中运行 `moistureSensor.py` 及以下参数：

端点  
您的自定义 Amazon IoT 终端节点。有关更多信息，请参阅 [Device Shadow REST API](device-shadow-rest-api.md)。

rootCA  
您的 Amazon IoT 根 CA 证书的完整路径。

cert  
 Amazon IoT 设备证书的完整路径。

键  
 Amazon IoT 设备证书私钥的完整路径。

thingName  
您的事物的名称（在本例中为 `RaspberryPi`）。

clientId  
MQTT 客户端 ID。使用 `RaspberryPi`。

命令行应如下所示：

`python3 moistureSensor.py --endpoint your-endpoint --rootCA ~/certs/AmazonRootCA1.pem --cert ~/certs/raspberrypi-certificate.pem.crt --key ~/certs/raspberrypi-private.pem.key --thingName RaspberryPi --clientId RaspberryPi`

尝试触摸传感器、将其放入花盆或放入一杯水中，查看传感器对各种含水量有何反应。如果需要，可以在 `MoistureSensorRule` 中更改阈值。当湿度传感器的读数低于规则的 SQL 查询语句中指定的值时，会向 Amazon SNS 主题 Amazon IoT 发布一条消息。您应会收到一封包含含水量和温度数据的电子邮件。

确认收到来自 Amazon SNS 的电子邮件后，按 **CTRL \$1 C** 停止 Python 程序。该 Python 程序发送的消息应该不足以产生费用，但完成后最好将其停止。