自制arduino_使用PHP和Arduino自制Twitter和Gmail通知

自制arduino

This article was peer reviewed by Claudio Ribeiro. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

本文由克劳迪奥·里贝罗 ( Claudio Ribeiro)进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!



I am a little obsessed with Twitter. It’s how I communicate with most of the developers I’m not fortunate to live in the same city as. I’m a little less obsessed with IoT projects, but then it’s harder to find the time to work on them than it is to check Twitter.

我对Twitter有点痴迷。 这就是我与大多数我不幸运要住在同一个城市的开发商进行交流的方式。 我对物联网项目的痴迷程度有所降低,但是找到工作时间比检查Twitter困难得多。

Unless I can do both at the same time.

除非我可以同时做两个。

Ever since the IoT week, I’ve been meaning to work on a project that will let me know when someone wants to speak to me. Something that looks cool, and is at the same time non-invasive. This is what I’ve come up with…

自从IoT周以来 ,我一直在从事一个项目,该项目将在有人想和我说话时通知我。 看起来很酷,同时又是非侵入性的东西。 这就是我想出的...

Arduino logo

Most of this code can be found on Github. I’ve tested it using PHP 7.1.

大部分代码可以在Github上找到。 我已经使用PHP 7.1对其进行了测试。

In this post I talk a lot about pins. I use this word to mean the pins coming out of components, as well as the Arduino sockets these pins go into. They’re often called terminals or ports. When I talk about pins, I just mean a place you can connect components or wires to. I’m quite specific each time though, so you’ll be fine!

在这篇文章中,我谈论了很多关于引脚的问题。 我用这个词来表示组件中的引脚,以及这些引脚插入的Arduino插座。 它们通常被称为终端或端口。 当我谈论引脚时,我只是指一个可以连接组件或电线的地方。 每次我都很具体,所以您会没事的!

该项目 (The Project)

The project we’re going to work on is a simple notification system, connecting a single RGB LED, a proximity sensor, and a PHP script to gather notifications. As notifications are received, the RGB LED will cycle through them, fading the LED to the appropriate color for each notification type.

我们将要进行的项目是一个简单的通知系统,它连接一个RGB LED,一个接近传感器和一个PHP脚本来收集通知。 接收到通知时,RGB LED将在它们之间循环,将LED淡化为每种通知类型的适当颜色。

Say someone has mentioned us on Twitter. The LED should periodically cycle to the Twitter blue. Then, if someone sends us an email, the LED should cycle between the Twitter blue and the GMail red. We could extend this to the Fitbit green, the Facebook blue and so on.

假设有人在Twitter上提到了我们。 LED应该定期循环到Twitter蓝色。 然后,如果有人向我们发送电子邮件,则LED应该在Twitter蓝色和GMail红色之间循环。 我们可以将其扩展为Fitbit绿色,Facebook蓝色等等。

If we’ve seen the Twitter notification, we should be able to wave our hand in front of the proximity sensor, and Twitter blue should be removed from the rotation, leaving GMail red etc.

如果我们看到了Twitter通知,则应该能够在接近传感器前面挥动手,并且应该从旋转中删除Twitter蓝色,而让GMail红色等。

硬体 (The Hardware)

We can use just about any RGB LED. As long as we can control the color it fades to, we can simulate the social network notifications we’re after. Really, just about any common anode RGB LED. If you get one that doesn’t include resistors, be sure to add those into your circuit. I’ll touch on that later…

我们几乎可以使用任何RGB LED。 只要我们可以控制其褪色的颜色,就可以模拟所关注的社交网络通知。 真的, 几乎任何常见的阳极RGB LED都可以 。 如果您得到一个不包含电阻的电阻,请确保将其添加到电路中。 我稍后再谈...

The more IoT work you do, the more likely you are to run into the terms anode and cathode. A common anode RGB LED is one that connects one pin to the positive pin on your micro-controller or battery, and three pins to ground, depending on the combination of colors you’re after.

您从事的物联网工作越多,遇到阳极和阴极的可能性就越大。 一个普通的阳极RGB LED是一种,将一个引脚连接到微控制器或电池的正极引脚,将三个引脚连接到地,具体取决于您所追求的颜色组合。

Connecting the red pin to ground will close the circuit so that current flows through the red portion of the LED. Connecting the red pin to a Pulse Width Modulation (or PWM) port on our Arduino, and grounding the port by half will reduce the amount of current flowing through the red portion of the LED.

将红色引脚接地将闭合电路,以使电流流过LED的红色部分。 将红色引脚连接到我们Arduino上的脉宽调制(或PWM)端口,并将端口接地一半,将减少流过LED红色部分的电流量。

Grounding the various pins by varying amounts will lead to many different colors – as many as you can define as CSS colors.

各种引脚的接地量不同会导致产生多种不同的颜色-可以定义为CSS颜色的颜色也一样多。

Next, we need some kind of proximity sensor. The easiest (in my opinion) is an infrared transceiver. You could also use an ultrasonic transceiver, but they’re better at mid-range (as they have a minimum sensing distance, so you’ll have to be further away from the sensor).

接下来,我们需要某种接近传感器。 最简单的(在我看来)是红外收发器 。 您也可以使用超声波收发器 ,但是它们在中距离处更好(因为它们具有最小的感应距离,因此您必须离传感器更远)。

Finally, we need an Arduino. You can use another micro controller, but this post will refer specifically to Arduino, because I have three within arms-reach, and nothing else to test on.

最后,我们需要一个Arduino。 您可以使用另一个微控制器,但是本文将专门针对Arduino,因为我有3个伸手可及的东西,无需测试。

将事物连接在一起 (Connecting Things Together)

Connecting the circuit

This is a relatively simple circuit, as far as they go. I’m by no means an expert, but I did manage to find the data sheets for the infrared sensor and RGB LED I bought; so connecting them up wasn’t too troubling.

就他们而言,这是一个相对简单的电路。 我绝不是专家,但我确实设法找到了我购买的红外传感器和RGB LED的数据表。 因此将它们连接起来并不太麻烦。

The important bits are that our LED pins are connected to PWN ports, so that we can gradually adjust the amounts of red, green, and blue, and that the sensor pin is connected to an analog port (in this case A0).

重要的一点是,我们的LED引脚连接到PWN端口,以便我们可以逐渐调整红色,绿色和蓝色的数量,并且传感器引脚连接到模拟端口(在本例中为A0 )。

You may be wondering why we don’t connect the LEG pins to analog ports, or why we don’t connect the sensor to a PWM port. PWM is designed to simulate degrees of on/off, but the way that is done is by turning something on for a fraction of a second.

您可能想知道为什么我们不将LEG引脚连接到模拟端口,或者为什么不将传感器连接到PWM端口。 PWM被设计为模拟开/关的程度,但是完成的方法是将某些东西打开几秒钟。

With the right frequency of on/off cycles, LEDs only appear to be partially bright. That’s a side-effect of our eyesight, in much the same way as thirty static images played in quick succession can appear to represent motion video.

在正确的开/关周期频率下,LED仅显得部分亮。 这就是我们视力的副作用,就像快速连续播放的三十幅静态图像可以代表运动视频一样。

We need the sensor connected to the analog port because we really do need a gradual measurement, and A0 will give us that.

我们需要将传感器连接到模拟端口,因为我们确实需要进行逐步测量,而A0可以做到这一点。

My RGB LED is fine with 3.3v and 200mA of current (before the resistors). So I can connect that to the 3.3v pin, and leave the 5v pin for the sensor’s power supply.

我的RGB LED可以使用3.3v和200mA的电流(电阻之前)。 因此,我可以将其连接到3.3v引脚,并将5v引脚留给传感器的电源。

My sensor also has a pin to enable/disable the sensor readings. I’ll code for this, but keep in mind that your sensor might also have this. If it does, connect it to any unused output pin (like 08 or 1213) and make sure you set that pin to high.

我的传感器还具有用于启用/禁用传感器读数的引脚。 我会为此编写代码,但请记住,您的传感器可能也有此代码。 如果是这样,请将其连接到任何未使用的输出引脚(例如081213 ),并确保将其设置为高电平。

We also need to connect the Arduino USB port to an open USB port on development machine.

我们还需要将Arduino USB端口连接到开发机器上的开放USB端口。

软体 (The Software)

Now let’s look at the software we’ll use to control things. Before we start telling the Arduino what to do, we should define some services:

现在,让我们看一下用于控制事物的软件。 在开始告诉Arduino做什么之前,我们应该定义一些服务:

namespace Notifier;

interface Service
{
    /**
     * Queries the service to trigger notification
     * alerts. Returns true if there are new
     * notifications to show.
     *
     * @return bool
     */
    public function query();

    /**
     * Marks the most recent notifications as seen.
     */
    public function dismiss();

    /**
     * Returns the name of this service.
     *
     * @return string
     */
    public function name();

    /**
     * Returns an array of pin color values,
     * for a common-anode RGB LED.
     *
     * @return int[]
     */
    public function colors();
}

This is from src/Service.php

这是来自src/Service.php

Each service we connect to needs to have a way for us to query for new notifications. Once we dismiss a notification type, we’ll also need to let the related service know.

我们连接到的每个服务都需要一种查询新通知的方法。 取消通知类型后,我们还需要告知相关服务。

Well need to be able to identify each service by a friendly name, and we’ll also need to know which light colors to associate with the service.

不仅需要能够通过友好的名称来标识每个服务,而且我们还需要知道与该服务关联的浅色。

连接到Twitter (Connecting To Twitter)

Communicating with Twitter means dealing with OAuth. There’s no point writing yet another abstraction for this, so we’re going to use a fairly popular Twitter library:

与Twitter进行通讯意味着要处理OAuth 。 为此没有必要再写一个抽象,因此我们将使用一个相当流行的Twitter库:

composer require endroid/twitter

We’re also going to need to create and store various API keys. Head over to https://apps.twitter.com/app/new and create a new application. You can use any callback URL, since we’re going to override it anyway.

我们还将需要创建和存储各种API密钥。 转到https://apps.twitter.com/app/new并创建一个新应用程序。 您可以使用任何回调URL,因为无论如何我们都将覆盖它。

Creating new Twitter applications

Creating new Twitter applications

创建新的Twitter应用程序

Note the consumer and access tokens and keys. Committing these kinds of things to Github is usually a terrible idea, so instead we’ll store them as environment variables. Let’s create a couple of files (called .env and .env.example):

注意使用者和访问令牌和密钥。 将这类事情提交给Github通常是一个糟糕的主意,因此我们将它们存储为环境变量。 让我们创建几个文件(称为.env.env.example ):

SERVICE_GMAIL_USERNAME=
SERVICE_GMAIL_PASSWORD=

SERVICE_TWITTER_CONSUMER_KEY=
SERVICE_TWITTER_CONSUMER_SECRET=
SERVICE_TWITTER_ACCESS_TOKEN=
SERVICE_TWITTER_ACCESS_TOKEN_SECRET=

This is from .env.example

这是来自.env.example

Before doing anything else, create a .gitignore file, and add .env to it. That’s where we will store the secret things, so we definitely don’t want to commit it to Github.

在执行其他任何操作之前,请创建一个.gitignore文件,然后向其中添加.env 那是我们将存储秘密内容的地方,因此我们绝对不想将其提交给Github。

Next, let’s create the Twitter notifier service:

接下来,让我们创建Twitter通知程序服务:

namespace Notifier\Service;

use Notifier\Service;
use Endroid\Twitter\Twitter as Client;

class Twitter implements Service
{
    /**
     * @var Client
     */
    private $client;

    /**
     * @var bool
     */
    private $new = false;

    /**
     * @var int
     */
    private $since;

    /**
     * @param string $consumerKey
     * @param string $consumerSecret
     * @param string $accessToken
     * @param string $accessTokenSecret
     */
    public function __construct($consumerKey, ↩
        $consumerSecret, $accessToken, $accessTokenSecret)
    {
        $this->client = new Client(
            getenv("SERVICE_TWITTER_CONSUMER_KEY"),
            getenv("SERVICE_TWITTER_CONSUMER_SECRET"),
            getenv("SERVICE_TWITTER_ACCESS_TOKEN"),
            getenv("SERVICE_TWITTER_ACCESS_TOKEN_SECRET")
        );
    }
}

This is from src/Service/Twitter.php

这是来自src/Service/Twitter.php

Generally, it’s a good idea to create dependencies like the Client outside the class, and bring them in as constructor parameters. But this client is just an implementation detail, and I have no interface to hint against. I think it’s OK to create a new instance inside.

通常,最好在类外部创建诸如Client之类的依赖项,并将其作为构造函数参数引入。 但是此客户端只是一个实现细节,我没有暗示的接口。 我认为可以在其中创建一个新实例。

The getenv function gets environmental variables – the same ones we defined in .env. We’ll load them shortly.

getenv函数获取环境变量–我们在.env定义的变量相同。 我们将尽快加载它们。

Let’s create the query method:

让我们创建query方法:

/**
 * @inheritdoc
 *
 * @return bool
 */
public function query()
{
    if ($this->new) {
        return true;
    }

    $parameters = [
        "count" => 1,
    ];

    if ($this->since) {
        $parameters["since_id"] = $this->since;
    }

    $response = $this->client->query(
        "statuses/mentions_timeline",
        "GET", "json",
        $parameters
    );

    $tweets = json_decode($response->getContent());

    if (count($tweets) > 0) {
        $this->new = true;
        $this->since = (int) $tweets[0]->id;
    }

    return $this->new;
}

This is from src/Service/Twitter.php

这是来自src/Service/Twitter.php

We’re going to be querying this service often, and until we dismiss the tweet notifications, we want them to continue showing on the LED. Therefore, if we previously found new tweets, we can return early.

我们将经常查询该服务,并且在我们消除推文通知之前,我们希望它们继续在LED上显示。 因此,如果我们之前发现了新的推文,我们可以早日返回。

If we’ve already queried Twitter for new tweets, we add its ID into the request parameters. That means we’ll only return new tweets in subsequent API requests.

如果我们已经向Twitter查询新推文,则将其ID添加到请求参数中。 这意味着我们只会在后续的API请求中返回新的tweet。

We already connected with the client in the constructor. So, we can immediately call the client->query method, fetching tweets from the mentions timeline. If there are any new tweets since the since ID, we report new tweets.

我们已经在构造函数中与客户端建立了连接。 因此,我们可以立即调用client->query方法,从提及的时间轴中获取推文。 since ID开始,如果有任何新的推文,我们将报告新的推文。

We just need to complete the interface:

我们只需要完成界面:

/**
 * @inheritdoc
 */
public function dismiss()
{
    $this->new = false;
}

/**
 * @inheritdoc
 *
 * @return string
 */
public function name()
{
    return "twitter";
}

/**
 * @inheritdoc
 *
 * @return int[]
 */
public function colors()
{
    return [1 - 0.11, 1 - 0.62, 1 - 0.94];
}

This is from src/Service/Twitter.php

这是来自src/Service/Twitter.php

We’ll see how to use this class shortly.

我们很快就会看到如何使用此类。

连接到Gmail (Connecting To Gmail)

We don’t have to use OAuth to connect to GMail, but we do have to enable IMAP, and generate an application-specific password. If you don’t already have IMAP enabled with PHP, refer to your installation’s/operating sytem’s help for doing that. When building from source, you can generally install it with the --with-imap flag. That also works with Homebrew on OS X:

我们不必使用OAuth来连接到GMail,但必须启用IMAP并生成特定于应用程序的密码。 如果尚未通过PHP启用IMAP,请参阅安装/操作系统的帮助。 从源代码构建时,通常可以使用--with-imap标志进行安装。 这也适用于OS X上的Homebrew

brew install phpXX --with-imap

XX is your PHP version number like 56 or 71

XX是您PHP版本号,例如56或71

To create a new application-specific password, head over to https://security.google.com/settings/security/apppasswords :

要创建新的应用专用密码,请转到https://security.google.com/settings/security/apppasswords:

Creating new Google application-specific passwords

Creating new Google application-specific passwords

创建新的Google应用专用密码

Once you have a new password, set it in .env, along with the email address you created it for. Next, let’s connect to GMail:

拥有新密码后,请在.env设置密码,以及.env创建密码的电子邮件地址。 接下来,让我们连接到GMail:

namespace Notifier\Service;

use Notifier\Service;

class Gmail implements Service
{
    /**
     * @var bool
     */
    private $new = false;

    /**
     * @var array
     */
    private $emails = [];

    /**
     * @var string
     */
    private $username;

    /**
     * @var string
     */
    private $password;

    /**
     * @param string $username
     * @param string $password
     */
    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }
}

This is from src/Service/Gmail.php

这是来自src/Service/Gmail.php

This looks similar to how we began the Twitter service class, but instead of creating a new Twitter client, we’re going to use imap_open to get a new inbox resource.

这看起来与我们开始Twitter服务类的方式类似,但是与其创建一个新的Twitter客户端,我们将使用imap_open获取新的收件箱资源。

As I discovered earlier, we need to reconnect each time we want to check for new emails. A curious side-effect of this IMAP client…

正如我之前发现的,每次要检查新电子邮件时,我们都需要重新连接。 此IMAP客户端的奇怪副作用……

Next, we need to create the query method:

接下来,我们需要创建query方法:

/**
 * @inheritdoc
 *
 * @return bool
 */
public function query()
{
    if ($this->new) {
        return true;
    }

    $inbox = imap_open(
        "{imap.gmail.com:993/imap/ssl}INBOX",
        $this->username, $this->password
    );

    if (!inbox) {
        return false;
    }

    $emails = imap_search($inbox, "ALL", SE_UID);

    if ($emails) {
        foreach ($emails as $email) {
            if (!in_array($email, $this->emails)) {
                $this->new = true;
                break;
            }
        }

        $this->emails = array_values($emails);
    }

    return $this->new;
}

This is from src/Service/Gmail.php

这是来自src/Service/Gmail.php

As I mentioned earlier, we need to reconnect to the IMAP server each time we want to see new emails. So, we do that, searching for all emails in the inbox. Then we compare what is returned with the list of previously cached message IDs. If there are any new ones, we report new emails.

如前所述,每次我们想查看新电子邮件时,都需要重新连接到IMAP服务器。 因此,我们这样做了,在收件箱中搜索所有电子邮件。 然后,我们将返回的内容与先前缓存的消息ID列表进行比较。 如果有任何新邮件,我们将报告新电子邮件。

Let’s finish up the rest of the interface implementation:

让我们完成其余的接口实现:

/**
 * @inheritdoc
 */
public function dismiss()
{
    $this->new = false;
}

/**
 * @inheritdoc
 *
 * @return string
 */
public function name()
{
    return "gmail";
}

/**
 * @inheritdoc
 *
 * @return int[]
 */
public function colors()
{
    return [1 - 0.89, 1 - 0.15, 1 - 0.15];
}

This is from src/Service/Gmail.php

这是来自src/Service/Gmail.php

Curiously, the RGB colors used in the YouTube and GMail logos are 226, 38, and 28. We subtract these from one because common-anode LEDs are brighter the lower PWM value we set. That’s because the lower PWM value we set, the more we ground the color pins, and grounding the pins leads to stronger current flow through the LEDs.

奇怪的是,YouTube和GMail徽标中使用的RGB颜色分别是226、38和28。我们将它们相减,因为共阳极LED在我们设置的较低PWM值下更亮。 这是因为设置的PWM值越低,彩色引脚的接地越多,而引脚接地会使流过LED的电流更强。

Let’s put these together with the Arduino code…

让我们将它们与Arduino代码放在一起...

连接到Arduino (Connecting To Arduino)

We don’t have a lot of time to go through the basics of Arduino PHP programming. Fortunately, I wrote another excellent post about it. Follow the instructions there, being sure to install the Gorilla extension (if you’re on OS X).

我们没有太多时间来学习Arduino PHP编程的基础知识。 幸运的是, 我写了另一篇有关它的精彩文章 。 按照那里的说明进行操作,确保安装了Gorilla扩展(如果您使用的是OS X)。

Once we’ve installed Firmata, we can install the Carica libraries:

一旦安装了Firmata ,就可以安装Carica库:

composer require carica/io dev-master@dev
composer require carica/firmata dev-master@dev

In addition, we also need to install that environment variables library:

此外,我们还需要安装该环境变量库:

composer require vlucas/phpdotenv

We can get things started by loading the environmental variables, and connecting to the Arduino:

我们可以通过加载环境变量并连接到Arduino来开始工作:

require __DIR__ . "/vendor/autoload.php";

use Dotenv\Dotenv;

(new Dotenv(__DIR__))->load();

use Carica\Io;
use Carica\Firmata;

$loop = Io\Event\Loop\Factory::get();

$board = new Firmata\Board(
    Io\Stream\Serial\Factory::create(
        "/dev/cu.usbmodem1421", 57600
    )
);

print "connecting to arduino...";

$board
    ->activate()
    ->done(function () use ($loop, $board) {
        print "done" . PHP_EOL;
    });

$loop->run();

This is from notifier.php

这是来自notifier.php

If you’re unsure what port to use (in place of my /dev/cu.usbmodem1421), type the following:

如果不确定使用哪个端口(代替我的/dev/cu.usbmodem1421 ),请键入以下内容:

ls /dev | grep usbmodem

Try each of the returned items, until you can successfully connect to the Arduino. Once that’s there, let’s initialize the pins:

尝试返回的每个项目,直到您可以成功连接到Arduino。 在那里,让我们初始化引脚:

// diode pins

$board->pins[10]->mode = Firmata\Pin::MODE_PWM;
$board->pins[10]->analog = 1;

$board->pins[11]->mode = Firmata\Pin::MODE_PWM;
$board->pins[11]->analog = 1;

$board->pins[9]->mode = Firmata\Pin::MODE_PWM;
$board->pins[9]->analog = 1;

// sensor pins

$board->pins[12]->mode = Firmata\Pin::MODE_OUTPUT;
$board->pins[12]->digital = 1;

$board->pins[14]->mode = Firmata\Pin::MODE_ANALOG;

This is from notifier.php

这是来自notifier.php

Not much to say about this. Each RGB LED pin is set to PWM mode, and their values are set to 1 (so that they LED appears to be off). Since my infrared sensor has an enable/disable pin, I need to set that pin to 1 (enabled). Finally, we set the sensor read pin mode to analog.

对此没有太多可说的。 每个RGB LED引脚均设置为PWM模式,并且其值均设置为1 (因此它们的LED似乎熄灭)。 由于我的红外传感器具有启用/禁用引脚,因此我需要将该引脚设置为1 (启用)。 最后,我们将传感器读取引脚模式设置为模拟。

Next, let’s connect to Twitter and GMail:

接下来,让我们连接到Twitter和GMail:

print "connecting to services...";

$services = new SplQueue();

$services->enqueue([
    new Notifier\Service\Twitter(
        getenv("SERVICE_TWITTER_CONSUMER_KEY"),
        getenv("SERVICE_TWITTER_CONSUMER_SECRET"),
        getenv("SERVICE_TWITTER_ACCESS_TOKEN"),
        getenv("SERVICE_TWITTER_ACCESS_TOKEN_SECRET")
    ), false
]);

$services->enqueue([
    new Notifier\Service\Gmail(
        getenv("SERVICE_GMAIL_USERNAME"),
        getenv("SERVICE_GMAIL_PASSWORD")
    ), false
]);

print "done" . PHP_EOL;

This is from notifier.php

这是来自notifier.php

We can enqueue each service we want to connect to in an SPLQueue. It’s a useful abstract for first-in-first-out (or FIFO) object storage. The second boolean parameter is whether of not the service has new notifications to display. We’ll change this as new notifications are detected and dismissed.

我们可以将要连接的每个服务放入一个SPLQueue 。 对于先进先出(或FIFO)对象存储,这是一个有用的摘要。 第二个布尔参数是服务是否具有要显示的新通知。 我们将在检测到新通知并将其关闭时进行更改。

Now, let’s set up a repeating check for new notifications:

现在,让我们为新通知设置重复检查:

$loop->setInterval(function () use (&$services) {
    $remaining = count($services);

    while ($remaining--) {
        $next = $services->dequeue();
        $next[1] = $next[0]->query();
        $services->enqueue($next);
    }
}, 1000 * 5);

This is from notifier.php

这是来自notifier.php

We can use the event loop’s setInterval method, which reoccurs every 1000 millisecond * 5 (or 5 seconds). We step through each service in the queue, pull it out, set whether or not it should display new notifications, and then put it back into the queue.

我们可以使用事件循环的setInterval方法,该方法每1000毫秒* 5 (或5秒)重复出现一次。 我们逐步检查队列中的每个服务,将其拉出,设置是否应显示新的通知,然后将其放回队列。

This is strange syntax, to be sure. But it’s just a side-effect of using the queue.

可以肯定,这是奇怪的语法。 但这只是使用队列的副作用。

Now we need to loop through the services again, changing the LED to their color in a rotation. We can set this to show one notification type every 4 seconds:

现在,我们需要再次遍历服务,将LED轮换更改为其颜色。 我们可以将其设置为每4秒显示一种通知类型:

$service = null;

$next = function () use ($loop, $board, &$next, ↩
    &$services, &$service) {

    $remaining = count($services);

    while ($remaining--) {
        $next = $services->dequeue();
        $services->enqueue($next);

        if ($next[1]) {
            print "showing {$next[0]->name()}" . PHP_EOL;

            $service = $next;
            break;
        }
    }

    if (!$service) {
        print "no notifications" . PHP_EOL;
        return;
    }

    $colors = $service[0]->colors();

    $board->pins[10]->analog = $colors[0];
    $board->pins[11]->analog = $colors[1];
    $board->pins[9]->analog = $colors[2];

    $loop->setTimeout(function () use ($board, &$service) {
        $board->pins[10]->analog = 1;
        $board->pins[11]->analog = 1;
        $board->pins[9]->analog = 1;

        $service = null;
    }, 1000 * 1.5);

};

$loop->setInterval($next, 1000 * 4);

This is from notifier.php

这是来自notifier.php

We use a similar loop syntax to loop over each service until we find one that needs to be displayed. If we find one, we pull it off the front of the queue and put it back at the end.

我们使用类似的循环语法循环遍历每个服务,直到找到需要显示的服务为止。 如果找到一个,则将其从队列的前面拉出,然后放回末尾。

Then, we fetch its colors and set the pins to the appropriate value. After 1.5 seconds, we turn the pins off again (by setting them back to 1). This $next function is called every 4 seconds.

然后,我们获取其颜色并将引脚设置为适当的值。 1.5秒后,我们再次关闭引脚(将它们设置回1 )。 $next函数每4秒调用一次。

Finally, we want to be able to dismiss notification types, by waving our hand in front of the infrared sensor:

最后,我们希望能够通过在红外传感器前面挥动手来消除通知类型:

$loop->setInterval(function() use ($board, ↩
    &$services, &$service) {

    if ($service !== null && ↩
        $board->pins[14]->analog < 0.1) {

        $remaining = count($services);

        while ($remaining--) {
            print "dismissing {$service[0]->name()}" ↩
                . PHP_EOL;

            $next = $services->dequeue();

            if ($next[0]->name() === $service[0]->name()) {
                $service = null;
                $next[0]->dismiss();
                $next[1] = false;
            }

            $services->enqueue($next);
        }
    }
}, 50);

This is from notifier.php

这是来自notifier.php

If there is a service currently displaying a notification, and the sensor is reading a value below 0.1, we take that to mean that there’s a hand in front of the sensor (and that it is dismissing the notification type).

如果当前有一项服务正在显示通知,并且传感器正在读取一个小于0.1的值,那么我们认为这意味着传感器前有一只手(并且正在消除通知类型)。

We loop through the services, telling the matching service to stop displaying notification alerts. We also call the dismiss method, so that the service will start checking for new messages again. This check happens every 50 milliseconds.

我们遍历这些服务,告诉匹配的服务停止显示通知警报。 我们还调用dismiss方法,以便该服务将再次开始检查新消息。 此检查每50毫秒进行一次。

结论 (Conclusion)

There are so many interesting things we can do using Arduino and PHP. This is just one useful project. While I was finishing this post, it let me know about multiple new emails and tweets. Now all I have to do is package it up in a project box, and I’ll be able to take it to work!

使用Arduino和PHP我们可以做很多有趣的事情。 这只是一个有用的项目。 当我完成这篇文章时,它让我知道了许多新的电子邮件和推文。 现在,我要做的就是将其包装在项目框中,然后我就可以使用它了!

Did you enjoy this? Perhaps you have ideas for the next project I can work on. Let us know in the comments below.

你喜欢这个吗? 也许您对我可以从事的下一个项目有想法。 在下面的评论中让我们知道。

翻译自: https://www.sitepoint.com/home-made-twitter-and-gmail-notifications-with-php-and-arduino/

自制arduino

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ros_arduino_bridge 是一个 ROS 软件包,它可以将 Arduino 板与 ROS 系统进行通信。下面是关于 ros_arduino_bridge 的安装和使用步骤: 安装: 1. 首先,在你的系统上安装 Arduino IDE。你可以从 Arduino 官方网站下载并安装适合你操作系统的版本。 2. 确保你的系统上已经正确安装了 ROS. 如果没有,请按照 ROS 官方网站的说明进行安装。 3. 在 ROS 中创建一个工作空间,可以使用以下命令: ``` mkdir -p ~/ros_arduino_bridge_ws/src cd ~/ros_arduino_bridge_ws/src catkin_init_workspace ``` 4. 将 ros_arduino_bridge 软件包克隆到你的工作空间中的 src 目录下: ``` git clone https://github.com/hbrobotics/ros_arduino_bridge.git ``` 5. 使用以下命令编译并安装软件包: ``` cd ~/ros_arduino_bridge_ws catkin_make source devel/setup.bash ``` 使用: 1. 首先,打开 Arduino IDE,并将你的 Arduino 板连接到电脑上。 2. 使用 Arduino IDE 打开 ros_arduino_bridge 软件包中的 Arduino 代码文件。代码文件位于 ros_arduino_firmware 文件夹中。 3. 在 Arduino IDE 中按下上传按钮将代码上传到你的 Arduino 板上。 4. 在终端中,使用以下命令启动 ros_arduino_bridge: ``` roslaunch ros_arduino_bridge arduino.launch ``` 5. 现在,你可以通过发布 ROS 消息来与 Arduino 板进行通信。例如,可以使用 rostopic 命令发布消息。可以通过查看软件包文档了解更多关于 ROS 消息和话题的信息。 以上就是关于安装和使用 ros_arduino_bridge 的简要步骤。通过这个软件包,你可以在 ROS 系统中与 Arduino 板进行通信并控制各种传感器和执行器。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值