本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

基于Particle Photon的家庭环境监视器

发布时间:2022-09-25
分享到:

基于Particle Photon的家庭环境监视器

发布时间:2022-09-25
分享到:

本文要介绍的是一个简单的可以为你家自己构建的环境监视器项目。该项目使用 Particle Photon、Adafruit 的传感器和一个 3D 打印的外壳。

我做这个项目的目的是为我的公寓建立一个环境监测系统。我想了解建造这样的东西需要什么。与此同时我还想看看传感器数据如何随时间变化,以及我是否可以检测到任何模式。

恰逢我有几个 Particle Photon,所以我决定尝试构建我的传感器网络,使用 Photon 作为处理器并连接到互联网。Particle 的硬件总是运行良好,他们基于云的 IDE 可以轻松编写和更新设备上运行的代码。将他们的设备连接到家庭 wifi 后,只需几分钟即可开始从连接的设备中提取数据。 

我的公寓里有三个房间,所以我知道我至少要制造三个这样的设备。但是我没有一次全部构建它们,并且我为每个都使用了不同的传感器,这样给我的代码增加了一些复杂性。理想情况下,我会一次购买该项目的所有硬件,这样它们就都一样了。不过事实正好相反,我将我已经拥有的传感器和组件拼凑在一起。 

每个传感器测量光照水平(以 lx 为单位)、温度、湿度、声音和振动。每个传感器设备上还有一个压电蜂鸣器,因此我可以提供有关设备状态的音频反馈。我现在用这个蜂鸣器做的就是在设备第一次启动时播放超级马里奥兄弟主题的片段。知道他们何时自我重置会很有用。 

该项目的另一个要求是让项目的案例看起来不错,因为这些设备将摆放在我公寓的每个房间里。我的公寓不是很大,所以他们真的没有地方好隐藏起来。正因如此,我想要一些简单实用且相当便宜的东西同时还能稍微美观一些。 

由于我是 3D 打印和快速制造的忠实粉丝,我决定自己设计并进行打印。我一直想尝试 AutoDesk Fusion 360,因此使用该工具为我的传感器构建外壳是有意义的。经过一些教程和视频后,我发现它非常易于使用。而结果也令我非常惊讶,比我预期的要好得多。 

我基于整个项目的板是 Adafruit 的 1/2 大小的原型板。起初构建这个板有点奇怪,我习惯于仅用普通的旧性能板构建电路​​并手动连接我自己的迹线。不过一旦您接受了电路板的接线约定,它实际上能使原型设计这一步变得非常快。

之后我又根据原型板设计了外壳,在完成之后,我就订购了我的 3D 打印件。大概需要 3 到 4 周,所以我有足够的准备时间在实物到达之前实际构建我的电路。

因此,在构建了其中的一些之后,我开始对我的组件的放置有了一点兴趣。在这里,您可以看到我的电路最新版本的一些照片。我将 Particle Photon 移到了板的顶部,这样我就可以为 microUSB 末端的小塑料位腾出空间。我发现,如果我将 Particle Photon 放在底部,并插入 microUSB 电缆,橡胶应变消除装置会将电路板从外壳顶部推出。 

我还从 Shapeways 订购了一些 3D 打印,不过这里只是为了进行比较。Shapeways 对于纯尼龙 3D 打印来说实际上要便宜得多。

为了实际查看来自这些传感器的数据,我遵循了 Particle 的关于如何使用 Librato 记录传感器数据的教程。 https://docs.particle.io/guide/tools-and-features/webhooks/#logging-to-librato

这是我公寓 7 天的数据。实际上并不是那么令人兴奋,因为波动可以看到不是很明显。这里的天气变化不大。我编写了一个小型 Heroku 应用程序,它从 WeatherUnderground 中提取我的邮政编码数据,并将该数据也发送到 Librato。这样我至少可以了解外部温度、湿度、光线等的背景信息。看起来很有趣,但我并没有真正发现任何重要的信息解析。另外,我认为测量声级的代码不正确。我需要重新审视这一点。我只是从一个音频 dbl 采样循环中抓取了一些代码,然后不加思索地把它放在那里。到这里,项目算是草草结束了,希望后续还能进一步做改进。

Prototype code for the Photon:

// This #include statement was automatically added by the Spark IDE.
#include "SFE_TSL2561.h"

// This #include statement was automatically added by the Spark IDE.
#include "AudioGetAverageLib/AudioGetAverageLib.h"

// TEMP/HUMIDITY SENSOR
// This #include statement was automatically added by the Spark IDE.
#include "Adafruit_DHT/Adafruit_DHT.h"
#define DHTPIN 2    
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#define TEMPSAMPLE 2000
int counter;

// Light sesnsor
#define HASLIGHT 1 // BC Sense 1 has light sensor 2561 from sparkfun, BC Sense 3 does NOT, BC Sense 2 has a 2561 light sensor fram adafruit

// Create an SFE_TSL2561 object, here called "light"
SFE_TSL2561 light;

// Global variables:
boolean gain;     // Gain setting, 0 = X1, 1 = X16;
unsigned int ms;  // Integration ("shutter") time in milliseconds


// AUDIO SENSOR
#define AUDIO_INPUTCHANNEL A0
//set the audio input board reference voltage
#define AUDIO_VOLTREF 0.0022
//set the audio input board reference dB value
#define AUDIO_DBREF 10
// The number of samples, eg 32
#define SAMPLE_COUNT 32
// Smoothing 0:more 64:less
#define SMOOTHFILTERVAL 48
#define DYNAMICBIAS 0

//set the reference ADC voltage
#define ANALOGVOLTAGEREF 3.3
double analogVoltageRef = ANALOGVOLTAGEREF; //ADC reference voltage

//initialize audioGet library
AudioGetAverageLib audioGet(
    AUDIO_INPUTCHANNEL,
    DYNAMICBIAS,
    AUDIOGETAVERAGE_DEFAULTBIASZERORAW,
    SMOOTHFILTERVAL,
    SAMPLE_COUNT,
    AUDIOGETAVERAGE_DEFAULTSAMPLESINTERVALMICROSEC,
    AUDIOGETAVERAGE_DEFAULTRMSCORRECTION);

// Spark variables used to store data values
double temperature;
double humidity;
double soundDbl;
double luxVal;
boolean lightGood;

// Sound generation
int speakerPin = A5;

// notes in the melody:
//int melody[] = {1908,2551,2551,2273,2551,0,2024,1908}; //C4,G3,G3,A3,G3,0,B3,C4
int melody[] = {2637,2637,0,2637,0,2093,2637,0,3136,0,1568,0};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
//int noteDurations[] = {4,8,8,4,4,4,4,4 };
int noteDurations[] = {8,8,8,8,8,8,8,8,4,4,4,4};

void song() {
    // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < arraySize(noteDurations); thisNote++) {

    // to calculate the note duration, take one second 
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000/noteDurations[thisNote];
    tone(speakerPin, melody[thisNote],noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(speakerPin);
  }
}

// Takes a command attribute to match method signature, we don't use it.
int playSong(String command)
{
    song();
    return 1;
}

void setup() {
    
    Spark.publish("BC2 Booted!");
    song();
    
    Spark.variable("temperature", &temperature, DOUBLE);
    Spark.variable("humidity", &humidity, DOUBLE);
    Spark.variable("sound_dbl", &soundDbl, DOUBLE);
    Spark.variable("lux", &luxVal, DOUBLE);
    Spark.variable("light_good", &lightGood, BOOLEAN);
    
    Spark.function("play_song", playSong);
    
    dht.begin();
    
    if (HASLIGHT){
        light.begin();
        // If gain = false (0), device is set to low gain (1X)
        // If gain = high (1), device is set to high gain (16X)
        gain = 0;
        // If time = 0, integration will be 13.7ms
        // If time = 1, integration will be 101ms
        // If time = 2, integration will be 402ms
        // If time = 3, use manual start / stop to perform your own integration
        unsigned char time = 2;
        
        // setTiming() will set the third parameter (ms) to the
        // requested integration time in ms (this will be useful later):
        light.setTiming(gain,time,ms);
        // To start taking measurements, power up the sensor:
        light.setPowerUp();
    }

}

void loop() {
    

    // do readings
    humidity = dht.getHumidity();
    temperature = dht.getTempFarenheit() - 8;
    Spark.publish("librato_bc2_humidity", String(humidity));
    delay(2000);
    Spark.publish("librato_bc2_temperature", String(temperature));
    delay(2000);

    // LIGHT
    if (HASLIGHT){
        unsigned int data0, data1;
        if (light.getData(data0,data1)){
            // Perform lux calculation:
            lightGood = light.getLux(gain,ms,data0,data1,luxVal);
            Spark.publish("librato_bc2_lux", String((int)luxVal));
            delay(2000);
        }else{
            lightGood = false;
            luxVal = 0.0;
        }
    }
    
    // AUDIO
    int audioRms = 0; //audio RMS value
    int audioAdc = 0; //audio raw ADC
    
    //get raw ADC
    audioAdc = analogRead(AUDIO_INPUTCHANNEL);
    //get RMS value
    audioRms = audioGet.getRms();
    double voltageRms = AUDIO_VOLTREF;
    if(audioRms > 0) {
          voltageRms = (audioRms * analogVoltageRef) / 4095;
          if(voltageRms < AUDIO_VOLTREF) { //prevent values less than AUDIO_DBREF
              voltageRms = AUDIO_VOLTREF;
          }
     }
    //get Spl value
    soundDbl = (double)audioGet.getSpl(voltageRms, AUDIO_VOLTREF, AUDIO_DBREF);
    Spark.publish("librato_bc2_dbl", String((int)soundDbl));
    delay(10000);
}

如果您对此项目有任何想法、意见或问题,请在下方留言。

以上内容翻译自网络,原作者:Brian Chamberlain,如涉及侵权,可联系删除。

加入微信技术交流群

技术交流,职业进阶

关注与非网服务号

获取电子工程师福利

加入电路城 QQ 交流群

与技术大牛交朋友

讨论