Apiary Assistant Report

Page 1


Senior Design Project Progress Report

EE 492 Senior Design Project

Apiary Assistant

Josh Farrell

Giancarlo Succi

May 3th, 2024

Faculty Advisor: Dr. Mohamed Salem,

Industry Advisor & Client: George Ellison

Acknowledgments

George Ellison, our client, who this project would not be possible without.

Dr. Farid Farahmand, for pitching the idea for our project and keeping us on track.

Dr. Mohamed Salem, for his availability, endless advising, critiques, and consultation.

Sharam Marivani, for everything he does in and around the labs.

Sonoma County Beekeepers Association

Theresa Giacomino

Luke Snyder

Center for Environmental Inquiry at Sonoma State University

Children’s Museum of Sonoma County

Abstract

Beekeeping is a daunting hobby for beginners to undertake. Assuming responsibility for thousands of tiny lives is a challenging task, especially when considering the bees’ survival is jeopardized by things as trivial as weather. Thus, it is essential for beekeepers to periodically open their hives to assess the conditions within and respond accordingly. This process is typically performed as seldom as the beekeeper’s skill allows to minimize interference with and damage to the hive, ecosystem, and bees within. In this report, we will examine an Internet of Things-oriented approach to bee monitoring. Our solution is a sensor-to-screen project that monitors conditions inside the hive to track the bee colony’s health, utilizing an embedded “Smart Frame” consisting of a microphone, temperature sensors and a humidity sensor slaved to a microcontroller housed outside the hive to reduce interference with the colony. The microcontroller takes the sensor data and transmits it over a ZigBee transceiver to a module inside the beekeeper’s home, which consists of another transceiver to receive the data, another microcontroller to extract the data, and a single-board computer acting as a gateway device to collect and upload the data to an online web server which the beekeeper can access via smartphone or computer to monitor conditions inside their hive. Our project, the Apiary Assistant, reduces beekeeper interactions with their hives while providing data critical to the hive’s survival.

1. Problem Statement

Domestic beehives are complex structures. They are secure and stable while closed but exposed to several risks while open. When sliding the frames out of the hive, the internal combs are exposed to potential harm. The honey filled comb attracts predators, and the exposed bees are unable to defend it. The comb can also be damaged, potentially destroying the comb or killing larvae within. The riskiest part is reassembly: when sliding the combs back into place, bees are swarming everywhere, it is almost impossible to not crush at least one bee between the comb and enclosure. Worse than that, there is risk of crushing the queen during reassembly. This is a considerable loss to the hive, setting it back weeks for a new queen to be born.

Our Apiary Assistant gives beekeepers the ability to remotely monitor their apiary, allowing them to stay informed on conditions inside their hive. This monitoring keeps the beekeeper up to speed with the wellbeing of their hive, allowing beekeepers to perform hive inspections less frequently thus reducing potential damage to the colony and comb.

2. Introduction

The single most fundamental part of beekeeping is opening the hive. It must be done to inspect the health of the hive, as well as harvest the honey produced inside. The process is simple and straightforward, yet detrimental to the hive’s health – whether on a commercial honey farm scale, or a single backyard hive. Opening a hive presents risks such as predation from wasps, damage to the comb, and harm to the larvae and bees within – potentially even the colony’s queen. The queen is the most important bee in the colony, responsible for producing all the colony’s bees and determining the fate of the hive. Should the queen die, it is a major setback for the colony at best and the death of the colony at worst. Beekeepers aspire to interact with their hives as seldom as practical to minimize unnecessarily exposing the hive to the elements and killing their bees. This abstract goal creates confusion for beekeepers, who are uncertain how often hive inspections are necessary. In this work, our goal is to give beekeepers enough information about their hives to eliminate the doubts and uncertainties about the hives’ wellbeing – all without having to pry open the hive for inspection. In the next section, we review some products that seek to do the same – reduce interactions between beekeepers and their hives by extracting data about the conditions.

3. Literature Review and Previous Works

Domestic beehives are fragile ecosystems notorious for their susceptibility to minor changes in their environment and staggering death rates – mortality rates between 20% and 90% deemed typical and acceptable.

The main cause of high bee mortality is due to parasites – Varroa Destructor, often called Varroa mites – which act as a vector for Deformed Wing Virus to infect hives [3]. To test for Varroa mites, beekeepers typically gather a cup full of between 100 and 300 bees, rinse them with alcohol and count the mites that are washed off. This process kills the bees but produces a reliable method of determining whether a hive is infested. The other major factor in bee mortality rates is hive climate; ideal hives are dry and hot, with an ideal humidity of 50% to 60%, and ideal temperatures between 94℉ and 96℉ [4]. High humidity is a death sentence for bees, as moisture whisks away the heat generated by bees to keep their hives hot and healthy, leading to hypothermia. Similarly, low temperature is a sign of a failing hive – indicating the bees are unable to create ideal conditions inside the hive –though low temperatures do not necessarily mean high humidity. The bees’ vulnerability to climate change and parasites necessitates beekeepers check their hives only when outside conditions are not averse to the hive’s survival, meaning inspections can only be performed when the climate allows.

The beekeeping market has undergone a lot of innovation in the past decade with the advent of versatile IoT technologies and complementary sensor integration, creating a new market for beekeepers wanting to monitor their hives freely and without disturbing the delicate ecosystem inside. Several companies have taken unique approaches to

Figure 1: Bee Losses by Year

information gathering and synthesis, many opting for “smart hive” products which collect data from hives, though they’re distinct from one another through where and how their physical devices are implemented in the hive, which devices are deemed necessary for customer satisfaction, how the collected data is transmitted and displayed, and interpreted. While all share the same goal of optimizing beekeepers’ workflow, they accomplish this with slightly different methods.

For instance, ApisProtect utilizes four sensors in a single module that attaches to the outside of the hive to gather temperature, movement, humidity, and sound data from the hive [5]. This data is wirelessly transmitted to a receiver that uploads it to a cloud. This cloud and its services are the main features that this product provides. Through an application, the processed data is displayed to the user. While a complex algorithm is not used to interpret the data, the user is notified of statistical outliers of each data type (temperature, humidity, etc.). This is a simple method to notify the user of anomalies or drastic changes in the hives.

BroodMinder offers a similar solution with the bonus of modularity via temperature, humidity, and weight sensors, GPS tracking, audio analysis, and cameras to adapt to any beekeeper’s needs for the right price [6].

BeeScanning is an avant-garde mobile application that offers an alternative to killing bees to test for mites, instead opting for a computer vision approach to recognizing Varroa mites on bees using the phone’s camera [7].

All of these technologies create value for beekeepers through providing alternative, nonintrusive ways to get feedback on the wellbeing of their colonies. Each one has its advantages and limitations, none are suitable for every beekeeper. Factors such as cost, installation, data type, and data delivery affect the target customer within the beekeeping market.

4. Methodology

We will solve the proposed problem by incorporating a microcontroller, microphone, temperature, and humidity sensor into a sort of “smart-frame” for Langstroth-configuration hives. The system will keep time using a real-time clock (RTC) to know when to sample data. The system shall have power delivered from a source external to the hive to minimize invasiveness to bees. Similarly, our communication module and antenna shall be external to the hive to ensure reliable transmission since the wire mesh in our smart frame would essentially create a faraday cage and prevent transmissions from making it out of the hive. The data will be uploaded to our gateway, which is connected to the customer’s internet router via an ethernet cable. The data will be processed and stored in a database for tabulation and display on a mobile app with simple GUI for usability. This will help beekeepers refrain from constantly disturbing their hives by giving them the tools to better understand conditions within without physical investigation.

Our solution differs from existing solutions in several ways. Notably, our group chose to incorporate a microphone into the sensor package for the purpose of analyzing frequency spectrums within the hive to perform anomaly detection; bees with deformed wing disease will flap their wings at a different frequency than healthy bees and often frequencies of the hive can change if infested with mites. Other solutions utilize external modules like laser gates or cameras to perform similar functions. Our solution also places a gateway in the customer’s home, eliminating the need for subscriptions to existing infrastructure such as LTE, and ensures the customer’s data is accessible without a paywall. Data taken from

Figure 2: System Block Diagram

inside the hive is transmitted via ZigBee, repeated using a relay node if distances are inhibitive, to an internet-connected gateway device which performs a Fast Fourier Transformation on the audio data and uploads an MP3 and PNG file to our database. Since both are files saved on the gateway, they can easily be read as binary data and defined as a variable within a python script. The resultant FFT data, interpreted as a PNG file using the Raspberry Pi’s MATLAB library, is uploaded alongside the MP3 audio data as BLOB files.

Transmission Intervals

Based on client feedback, it was decided to transmit temperature and humidity from the hive node every hour. Audio samples will be transmitted every four hours, alongside temperature and humidity. Temperature and humidity will always be transmitted first, as it only requires a single packet and can be transmitted and quickly uploaded to the database from the gateway. As opposed to audio which requires two thousand-four-hundred and sixty packets and takes significantly longer to transmit and upload.

Real Time Clock

The hive node’s microcontroller will periodically enter deep sleep mode to reduce power consumption when not in operation. To wake up the microcontroller at consistent intervals, an external real time clock (RTC) is used. The RTC will keep accurate time, reduce clock drift, and be independent of the microcontroller’s internal clock.

Gate Driver

Lowering power consumption is critical to the design of the Hive Node. Unnecessary current draw would reduce battery life. Hence, implementing a way to interrupt power draw when the transmitter is not in use was necessary. This was achieved by using a high-side MOSFET gate driver with the MRF transmitter. When the microcontroller goes into sleep mode it will set a low on the GPIO pin connected to the gate of the MOSFET. This will cut off the power supply from the transmitter. When the microcontroller wakes up from sleep mode it will set the GPIO pin to high and activate the MOSFET, restoring power to the transmitter.

Figure 3: Gate Driver Circuit

Relay Node

To expand the communication range between the Hive Node and Home Module, an intermediary transceiver node was implemented. This node consists of only a transceiver and microcontroller. When it receives a packet from the hive node, it will add its contents to a row in a character array. It will repeat this until it has not received a packet for twenty seconds. Once twenty seconds have passed it will transmit each row of the character array in the order it received them. This node will operate the same no matter what packet type it receives, audio or temperature / humidity. The difference in operation will simply be relay only one packet for temperature / humidity or many packets for audio.

Interfacing Microcontroller to Gateway

The microcontroller will pass the received transmission contents to the gateway via I2C. The Gateway will be initialized as a master device and the microcontroller as a slave device However, an I2C slave cannot initiate communication The gateway must be prompted to initiate I2C communication when the microcontroller has received a new packet. When the microcontroller receives a new transmission, it will save its contents to a character array ready to be sent to the I2C bus. Then it will momentarily set a GPIO pin wired to the gateway to high. The gateway will read this pin high and initiate I2C communication and read the transmission contents from the I2C bus.

Interpreting Received Packets

The hive node will transmit two types of packets, packets containing audio values and a packet containing temperature and humidity values. For the home module to properly process both audio and temperature / humidity values, we must add an identifier to the temperature / humidity packet. The gateway will read the contents of the packet. If it sees the identifier for temperature / humidity it will take the payload and extract the two temperature values and one humidity value. It will immediately run a python script that will connect to the SQL database and insert these values into the designated table. If it receives a packet containing audio it will save the payload to a row of an array and continue to do this until it no longer detects incoming packets. It will then proceed to run a script that reconstructs the audio into an MP3 file and produces an FFT of the audio sample.

Uploading MP3 and PNG files to database

Utilizing the MySQL Connector driver, we can have the python script connect to our database and insert these binary files as BLOBs (Large Binary Object) and the current date and time as the DATETIME data type into the audio table. Once inside the database, an

additional PHP script is used to parse the BLOB data into both their PNG and audio forms, storing them on a webpage for access by the mobile application.

5. Challenges and Risks

Our project faces a handful of risks and many challenges on the way to our minimum viable product. In terms of risks, the foremost issue is the fragile nature of bees and their delicate habitat. As was touched on in the Literature Review and Previous Works section, bees die a lot. One major risk to our project is losing our prototype's colony, whether that be due to swarming, disease, climate, et cetera. We were fortunate enough to avoid this risk through sheer luck, as two of our client's five hives swarmed and left their apiaries while our prototype hive was unaffected.

Another risk similar to the above, but within our control, is our team accidentally harming the colony as we perform installation of our prototype and inspection. If we destroy brood comb or kill the colony's queen, that will compromise the hive's survival. Our group has mitigated this risk through a release of liability form signed by the group members and our client.

Moving onto challenges, one major challenge is constructing the hive node such that it inhibits or at least discourages the bees from building on it. This is important because the sensors on the node need to be able to accurately measure conditions inside the apiary, meaning the sensors must be unobstructed by comb and propolis. We plan to accomplish this by creating a hive node frame out of smooth, non-porous material to discourage bees from constructing comb and propolis. Implementation of our prototype frame into a “very active hive” (our client’s words) in late January through late March showed success, as bees built propolis and comb on either side of the prototype frame but not on it. More on this in System Test 3.

Figure 4: Database Audio Table

Another challenge will the process by which we take data from the hive and make it available to our client to view; this process will involve microcontroller to microcontroller, microcontroller to gateway, gateway to database, and database to mobile application communication. Our group has relevant experience with most of the above across several previous classes, though tying it all together to work as one will prove difficult -- namely the database to mobile application communication, which we have no experience with. To overcome this challenge, the group decided on using the mobile app development suite MIT App Inventor, which simplifies the application development process greatly and has tools to help interact with databases as well as graph the information obtained from the database. The most challenging aspect of this integration will be writing PHP code to pull the data from the database for parsing in-app. Regarding microcontroller communications, our group had to overcome the challenge of transmitting audio data through ZigBee -- a communications protocol none of us were familiar with. Using existing libraries for our ZigBee transceiver, the group ran into the problem of data size when sending audio; our desired fast Fourier transform resolution dictated a sampling frequency of 2048 Hz over a five second sample, creating 10,240 data points to be transmitted to the database. The existing library code for transmitting could only accept a few values per packet, thus the group had to overcome this by writing code to divide the audio array into chunks to be sent one at a time, and subsequently create a retransmission protocol to ensure packet delivery.

One final challenge we faced was meeting the 10-day autonomy requirement laid out by Marketing Requirement 3. As the group navigated through other challenges and revised the hive node’s code and layout, prior current draw tests became obsolete; for this reason, our group forewent deciding on a battery until the final version of the hive node was completed.

6. Project Requirements

6.1 Marketing Requirements

MR-1. System will measure the internal temp, humidity, and audio of the hive

MR-2. System will wirelessly transmit from the user's backyard to their home

MR-3. Battery life of at least 10 days

MR-4. Compatible with medium as well as deep bee box hives

MR-5. System will include relay node for transmitting beyond maximum range

MR-6. Data will be accessible from computers and mobile devices

MR-7. System will be non-invasive and non-harmful to the bees

MR-8. Database will have adequate storage for a year’s worth of data

6.2 Engineering Requirements

ER-1. Temperature sensors shall have an accuracy of up to ± 3℉ when measuring from 50 to 102℉ [MR1]

ER-2. Audio shall be recorded at 2048 samples per second, to produce a spectrum of 1024 Hz with a resolution of 32 Hz [MR1]

ER-3. The system shall have a maximum transmission range of 50 m; Relay node, if necessary, shall provide an additional 50 m of transmission range [MR2, 5]

ER-4. Hive node peak current draw shall not exceed 375 mA [MR3]

ER-5. Device shall be modularly compatible with both medium and deep boxes(supers) of dimensions 19 3/16in (L) x 1in (W) x 6 1/4in (H). [MR 4]

ER-6. User interface shall be a PHP webpage to query and visualize data. [MR 6]

ER-7. Battery and transceiver enclosure on hive node shall be IP55 compliant [MR 7]

ER-8. Database shall have at least 100 megabytes of storage to accommodate a year’s worth of data [MR 8]

7. Implementation

7.1

System Architecture

Our project will consist of two main modules and one sub module depending on customer needs. The Hive Node which will transmit data via a microcontroller, Home Module, which will receive data transmitted from the hive, and our relay, which will serve as a wireless connection extension if the customers apiaries are out of expected transmission distance. Our Hive Node will reside within the hive and collect data. It will have a temperature sensor, humidity sensor, and microphone. The Home Module will take the

data and upload it to a database where it will be tabulated and organized. The database will have a PHP script meant to be accessed by the mobile application that prompts for date and returns the relevant data (FFT PNG, MP3 file of bee audio, temperature, and humidity data). The mobile application will be designed in MIT App Inventor, using its tools for SQL connection and HTTP requests to pull data based on user input. The relevant information will be displayed across a graph displaying temperature and humidity over the date range, and FFT images and MP3 files corresponding to samples taken over the requested timeframe.

Figure 5: Hardware Block Diagram
Figure 6: Hive Node Circuit Schematic
Figure 7: Hive Node Flow Chart
Figure 8: Hive Node prototype
DHT20
Figure 10: Relay Node Software Flowchart
Figure 9: Relay Node Circuit Schematic
Figure 11: Relay Node Prototype ESP32
MRF24J40
Figure 12: Home Module Circuit Schematic
Figure 13: Home Module Software Flowchart
Figure 14: Home Module prototype
MRF24J40

7.2 Alternative Design Matrix

Table 1: Microcontroller Decision Matrix

0.32

(520 kB)

(24mA)

(30 mA)

(2 kB)

(19 mA)

When choosing our microcontroller, we weighed RAM to be the top priority so the worry of storing all necessary data would be eliminated. Current was our second consideration to meet our 10-day autonomy requirement. Third and least important criteria was clock speed since all data will be fairly quick to measure anyway with the exception of audio. Since we are not monitoring the hive in real-time around the clock, we don't need anything faster than 120 MHz. The ESP32 microcontroller was chosen.

Table 2: Temperature Sensor Decision Matrix

(1180 mm3)

The temperature sensor was one of our most important components since the condition it measures is a critical condition to bees' survivability. Since bees are at risk at temperatures below 50॰F or above 102॰F we need to ensure that we have accurate temperature readings as our priority. Secondly, since we are integrating our sensors into a frame-shaped suite, size is our second priority with power consumption being a close third. All microphones weighed were similar across size and accuracy, thus the TMP35 was chosen for its low power consumption.

Table 3: Microphone Decision Matrix

Parameter

Weights for the microphone decision matrix were minimal as all models met other criteria in other considered categories. For this reason, we only weighed sensitivity and SNR against each other. Sensitivity was our top priority due to the nature of the range of frequencies we wish to capture (100 Hz to 500 Hz). The matrix concluded that the CMA 4544PF-W would be our microphone of choice.

4:

We decided power consumption was the most important criteria to minimize for our project and weighed it accordingly. Typically, price discrepancies aren’t significant enough to warrant putting on decision matrices, but the difference between $30 and $130 was too large to ignore, so we factored the prices into our matrix. Finally, bandwidth was our least important consideration, as the packets we are transmitting shouldn’t exceed a couple kilobytes. Using those criteria, the matrix determined ZigBee to be the best fit for our project.

Table 5: RTC Decision Matrix

Table
Wireless Communication Decision Matrix

Documentation

Weight: 0.57

( Good doc. )

( Some doc. ) Ship Time Weight: 0.29

( 1 day )

( 0.3 mA )

( 4 days )

The real time clock was a late add-on as we realized our microcontroller’s onboard clock was too imprecise for the sampling intervals we required. Subsequently, documentation and ship time were the most important parameters. Documentation was measured arbitrarily through browsing existing projects. Because of better documentation, ship time, and current characteristics, the DS3231 was chosen.

7.3 Budget / Parts List

Table 6: Parts List

7.4 Project Schedule

Before our group touched any components, we had to understand what we wanted to accomplish. We spent the first couple months of the semester researching bees and what affects them, wireless communication methods, and doing community outreach. The group joined the Sonoma County Beekeeper’s association, and a friend of Gabe’s recommended going to the Children’s Museum of Sonoma County to talk to the bee panel that was presenting there; at CMSC, we met our eventual client George, who we’ve consulted and worked with over the course of the project. Regarding extracurriculars, in November we applied for and were granted funding from the Sonoma State University Center for Environmental Inquiry. In February, we applied to the California State Research competition and the IEEE Sustainable Technology convention; we were accepted to present at the SUSTECH convention and will be doing so in the first half of April.

Our project originally consisted of two main physical parts: a hive and home. To maximize our use of time, we worked on both concurrently starting in the second half of November when our parts arrived.

For the hive node, we divided tasking with Gabe assigned to hardware and Josh working on software, Giancarlo helping with both. Gabe developed prototype frames in CAD over the course of the whole project. The first major development was interfacing the microcontroller with the transceiver, accomplished in early January, which allowed the group to begin performing initial transmission tests. Further work on interfacing microcontroller with new sensors was undertaken by Gabe and Giancarlo intermittently through late March. Josh and Giancarlo developed the transceiver-microcontroller integration further as more systems were implemented, and Gabe created code to record microphone audio. Regarding hive node tests, Gabe performed initial power delivery tests in November which were deemed insufficient by the technical panel, requiring revisitation through December. Upon the completion of microcontroller-transceiver integration in January, the group performed preliminary current draw and range tests. Gabe then undertook characterizing the microphone through February. Towards the end of February after the successful implementation of the microphone, another range test was performed at our client’s property in pouring rain (suboptimal conditions), where it was concluded our range was insufficient for our client’s needs – this was the impetus for the relay node. Another range test is to be performed upon completion of the relay node. From late February through March, Giancarlo characterized the temperature and humidity sensor, and Gabe completed an IP55 verification test on the hive node external housing.

For the home module, all development cruxes on interfacing the microcontroller with the gateway, as the home module’s operation depended on retrieving data from the

microcontroller. Josh finished this in early January, and made code to read I2C data from the microcontroller on the Raspberry Pi gateway. Giancarlo took charge of setting up the database and refining the transceiver gateway code from January through February while Gabe began working on prototyping the mobile app design in MIT App Inventor. In the first half of March, the group came together to work on getting all datatypes into the database; Giancarlo was able to get BLOB files into the database, and Josh made a PHP script to interpret them for display on the mobile app. Josh is currently working on connecting the app to the database to display our data. Moving onto tests, the group was able to receive data on the home module at the beginning of January when the transceiver was interfaced with the microcontroller. Next, in February, Giancarlo successfully uploaded data from our home module to the database, and the group worked together in March to accomplish our data to database test, successfully tabling all our datatypes. The remaining test is to view our data on the mobile app, which Josh will finish in early April.

Lastly, the relay node. The need for our relay node emerged after our failed range test in February. Josh wrote the code for the module and Giancarlo assembled the circuit, taking over coding. The relay node was completed in early April, and another comprehensive range test for the system with and without the relay was performed. Aside from some code debugging, this marks the effective end of the project’s development.

From mid-April out, all that remained was physically implementing the sensors inside of our 3D printed frame. This was undertaken over the weekend of April 27th by Giancarlo and Gabe after the group’s technical presentation on the 26th in preparation for the 2024 Sonoma State University Research, Scholarship, and Creativity Symposium.

Figure 15: Gantt Chart showing distribution of tasking

8. List of Tests and Results

8.1 Summary of Tests

Table 7: Function Tests

Hive node current draw

FT.2 Temperature sensor characterization

FT.3 Validate we can capture expected frequencies pertinent to bee audio (100550 Hz)

FT.4 Expected range of transmission is at least 50m

Table 8: System Tests Test Number

Hive Node Wireless Transmission

Frame power/TX solution

Mire-Mesh Frame Test to Protect Sensors

8.2 Description of Tests

Function Test 1: Current Draw – Attempt 1 (January, 2024)

Objective:

Test the hive node’s peak current to test whether we meet our requirement of less than 375 mA peak current.

Setup:

The test requires our frame, power supply and, and transceiver to be implemented. This test will also require an ammeter capable of measuring peak current over a time interval.

Procedure:

An ammeter will be attached to the positive contact of our power supply on one end and connected to the Vcc of the module at the other end. We will begin a timer for 10 minutes.

16: Current Draw Test Setup

Pass/Fail Criteria:

If the peak current measured through our module does not exceed 375 mA, the test passes. Should the peak current exceed that, the test is immediately a failure.

Notes:

Figure

While deemed sufficient for the early stages of the project, 375 mA is not only high, but also a test shouldn’t be determined by the peak current. Thus the decision was made to do the test again with average current instead.

Function Test 1: Current Draw – Attempt 2 (April, 2024)

Objective:

Test whether the hive node’s average current is below 50 mA for its four hour cycle.

Setup:

Much like the initial test, only with more code and a better understanding of the current meter used, which has an error of 0.5% plus or minus 2 μA.

Procedure:

The hive node, fully prototyped with functional code, was connected to the USB current meter, which was connected to a laptop to view the microcontroller’s serial monitor while providing power to the circuit. The test was run for four hours, during which the hive node sampled temperature and humidity each hour, and audio once.

Pass/Fail Criteria:

Should the current exceed 50 mA – a number derived from size constraints of our battery fitting inside our IP-55 container – the test is a failure. Otherwise, it is a pass.

Function Test 2: TMP35 Characterization

Objective:

To ensure that the TMP35 measures temperature within ± 3°F of the true value when measuring from 50 °F to 102 °F.

Setup:

The TMP35 will be supplied with 3.3v and its output measured with a multimeter. Jumper wires will be used to connect input voltage, ground, and output so that the TMP35 can be easily positioned while functioning. The TMP35 and its connectors will be wrapped in a small amount of cling wrap for water proofing Both the TMP35 and the probe of the digital thermometer will be submerged in a container of water.

Procedure:

The output of the TMP35 and digital thermometer will be measured with the digital thermometer acting as the reference. The temperature of the water will be swept through the desired temperature range. This will be done by either dropping an ice cube or pouring hot water into the container. As the temperature gradually changes, the output voltage and corresponding thermometer reading will be recorded at regular intervals. With this data, the TMP35’s temperature reading can be calculated.

Pass/Fail Criteria:

If the difference between the minimum TMP reading and maximum thermometer reading exceeds -3°F or the difference between the maximum TMP reading and minimum thermometer reading exceeds +3°F, then the test is a failure.

Function Test 3: CMA4544PF-W Frequency Response

Objective:

To validate that our chosen microphone module, the MAX9814 captures frequencies of interest that are pertinent to bee buzzing audio. (120 - 900 Hz). In addition, we want to complete an uncertainty analysis for the DSOX2002A Keysight oscilloscope.

Figure 17: TMP35 Test Setup

Setup:

The setup for testing uses a JBL Clip2 speaker that will play generated signals of known frequencies between 120 Hz and 900 Hz. Using these generated signals from MATLAB, we will play them into our MAX9814 CMA microphone module at fixed distance of 8cm, and at a fixed volume for all frequencies and observe and measure the frequency response. The setup will utilize the Keysight DSOX2002A Oscilloscope and the voltage supply benches we have in the lab.

Procedure:

Play MATLAB generated signals into MAX9814 CMA microphone module and measure the frequency response from 120 Hz - 900 Hz in increments 50 Hz. Following testing, the uncertainty analysis of the DSOX oscilloscope will be calculated for all measured points.

Pass/Fail Criteria:

The test passes if all frequencies of interest are captured and the uncertainty analysis is completed for the uncertainty of the oscilloscope.

Notes:

Microphone characterization is hard, and expensive. To properly characterize the microphone, a calibrated microphone is needed; such hardware is beyond the scope of this project. Subsequently, this test should be noted more as a verification of function test rather than a true microphone characterization, as the goal is to verify the microphone’s frequency response resembles that on its datasheet and is thus suitable for our applications.

Figure 18: Microphone Test Setup

Function Test 4: Transmission Range Test without relay

Objective:

Ensure that our range of transmission between the Hive Node and Receiver Module is at least 50 meters.

Setup:

The prototyped hive module and home module were separated by 50 meters on a flat open field in full sun

Procedure:

With both the transmitting and receiving nodes set up, both are powered on, and the hive node begins sampling and transmitting audio, temperature, and humidity.

Pass/Fail Criteria:

If the home module can successfully receive all audio packets transmitted by the hive module, the test is a pass. Otherwise it is a failure.

Function Test 5: Transmission Range Test with relay

Objective:

Test whether our relay module extends the system’s range by at least 50 meters.

Setup:

The prototyped hive module, relay, and home module were separated by 50 meters each on a flat open field in full sun.

Procedure:

With all nodes set up, all were powered on, and the hive node begins sampling and transmitting audio, temperature, and humidity.

Pass/Fail Criteria:

If the home node successfully receives all audio packets transmitted from the hive node at a distance of 100 meters (50 meters from the relay), the test is a pass. Otherwise it is a failure.

Function Test 6: IP55 Compliance Test

Objective:

Ensure the power supply and transmitter’s housing provide adequate protection from water and dust/dirt ingress.

Setup:

Four moisture strips will be houses in the IP55 rated container. A garden hose was used to test water ingress.

Procedure:

The test is simple, we spray water from a garden hose at all angles of the IP55 container and hope that water does not breach the box and affect the sensitive moisture strips

Pass/Fail Criteria:

If there is no water breach and as a result, no altered moisture strips, the test passes. Should water make it into the containers and the moisture strips have been altered and react, the test will be ruled as a failure.

Figure 20: IP55 container water ingress test
Figure 19: IP55 container and moister strips

System Test 1: Wireless Transmission

Objective:

The objective of this test is to transmit 10240 Analog-to-Digital (ADC) samples that were captured from our microphone at the hive-node and successfully receive them in 2560 packets each containing four ADC samples at our home-node. It must be ensured that frequency spectrum of the audio sample is not altered or distorted during transmission

Setup:

This test requires that the hive-node and home-node transmission is already working as well as having working audio sampling. The setup primarily includes two MRF transceivers, one at the hive-node and one at the home-node, the MAX9814 microphone module and MATLAB software to use as a reliable comparison.

Procedure:

The procedure for this test entails sampling 5 seconds of audio at the hive-node and transmitting it via our MRF transmitter to the home-node's ESP32. The ESP32 then must relay that data to our Rpi3 through I2C communication. Afterwards the Raspberry Pi will save the received data from the I2C bus into a text file called values.txt. Once all 10240 values are received, another script will automatically extract all audio samples from the text file and reconstruct the array as it was at the hive-node. After the array is reconstructed, an MP3 file will be created from the processed audio samples and a plot will be generated and saved as a PNG showing the FFT of the audio from 0 Hz to 1024 Hz. In MATLAB the root mean square error of the two FFTs will be c

Pass/Fail Criteria:

Figure 21: Wireless Transmission Setup

The pass-fail criteria depend on how much the pre transmission spectrum and post frequency spectrum differ. If the spectrums have a root mean square error of 5% or less this test is considered a pass. If it exceeds 5% then it’s a failure.

System Test 2: Power Delivery Under Pressure

Objective:

Achieve reliable power delivery to the hive node through a Flat Flexible Cable (FFC). The goal is to prototype a method of power delivery to the “smart frame” while it’s inside the hive and supported by the notches within. The power supply will be external to the hive so it is required that the ribbon cable that is compressed between the edges of hive supers and should withstand at least 70lbs to simulate the pressure of a honey-bearing super. The FFC cable for this test should withstand the pressure and sustain power delivery for at least 2 hours.

Setup:

The ribbon cable will be connected to a battery on one end and a microcontroller on the other. A weight of 60 pounds will be placed directly on the ribbon cable and left there for a prolonged period of time.

Procedure:

Weight was piled onto a scale which read more than 80 lbs. These items were placed atop the apiary super to simulate the pressure that honey bearing frames would apply to the FFC cable.

Pass/Fail Criteria:

Figure 22: Ribbon Cable Power Delivery Under Pressure

The FFC should withstand a pressure of at least 70lbs for 2 consecutive hours to show that power delivery under pressure of a honey-bearing super will not create issues over time.

System Test 3: Preventing Comb & Propolis Accumulation on Smart-Frame

Objective:

The objective of the test was to find a means of preventing the colony from covering the frame in comb and propolis to protect the sensors housed within. In addition to protecting them this would help ensure that the conditions and the audio that’s measured, more accurately reflect real conditions. In the case that a sensor gets coated in comb or propolis this can result in higher or cooler temperatures due to compromising the sensor If the microphone may get covered in propolis, the audio may be muffled and not reflect the true frequencies of the hive

Setup:

The set up was simple, a standard Langstroth hive frame was put together with a fine wire mesh on both sides. The sharp edges of the mesh were wrapped in smooth duct tape to ensure that the bees were not harmed by the ends of the wires.

Procedure:

After the frame was built it was stored inside a very active hive for 2 months from January 25th to March 26th . The frame was placed in the third slot from the end of the super and was not moved between these dates.

Pass/Fail Criteria:

If a lot of comb or propolis is accumulated on the mesh and the frame to the point that the group deems it to be detrimental to the sensors, then the test will be ruled as a pass. If the frame remains clean and uncovered and it is clear that the sensors will remain uncompromised, this test will be ruled as a pass.

Figure 23: Langstroth hive frame with wire mesh

8.3 Summary of Results

Function Test 1: Current Draw (January, 2024)

Results:

After measuring the Hive Node’s current draw for 10 minutes, we recorded a peak current draw of 71.7mA. To account for the tolerance of the amp meter, we express our peak current as 71.7mA ∓(0.5% + 2 µA). This gives us a range of 71.33 to 72.06 mA for peak current draw. This current range falls well below our minimum requirement of 375mA, indicating that this test is a pass. The group noted here that peak current isn’t helpful for determining autonomy, as average current is a better metric. The following current tests were altered accordingly.

State of Test: Passed

Function Test 1: Current Draw (April, 2024)

Results:

Following the addition of sleep mode to our microcontroller and working within the size constraints for our IP-55 container, the new goal average current was set at 50 mA. The hive node achieved an average current of 13.7 mA ∓(0.5% + 2 µA), or 13.6 to 13.8 mA.

Figure 24: Amp Meter recorded peak current

State of Test: Passed

Function Test 2: TMP35 Characterization

Results:

56 data points were collected (sensor voltage, reference temperature) with the reference temperature ranging from 49.1°F – 117.14°F. Plotting the sensor’s voltage output vs the reference temperature revealed they had a linear correlation with a R squared value of 0.99. After accounting for the accuracy of the multimeter and digital, a minimum and maximum was determined for the sensor temperature and reference temperature, for each data point. Among all the data points, the largest difference between the sensor minimum and the reference maximum was -2.69 °F. The largest difference between the sensor maximum and the reference minimum was +2.68 °F. These values are within our ER1 of ±3

°F, therefore the test is a pass. y = 0.9996x + 0.0266 R² = 0.9996

DHT35 ( ° F)

Figure 25: DHT35 temperature vs reference temperature

State of Test: Passed

Function Test 3: CMA4544PF-W Frequency Response

Results:

The test was ruled a pass. Preliminary results with just the CMA microphone were not successful as the amplifier circuits we built did not have sufficient gain for an ADC to detect the output. For this reason, we switched to a breakout module that is equipped with the same microphone. This module was the MAX9814. During testing, the 100 Hz frequency was not consistently captured, however, after referring to the datasheet of the JBL Clip2, it became apparent that the speaker is only designed to output frequencies as low as 120 Hz and as high at 20 kHz. Due to financial constraints, purchasing an ultra-low frequency output speaker was not feasible. Due to our constraints and considering our success in reading frequencies as low as 120 Hz and up to 900 Hz accurately, we still ruled this test as a pass. The MAX9814 is a viable component for our project.

Figure 26: DHT35 voltage vs reference temperature

State of Test: PASS

Figure 27: Microphone Frequency Response (Datasheet)
Figure 28: Microphone Frequency Response (Measured)

Function Test 4: Transmission Range Test without relay (February 19, 2024)

Objective:

The objective of the transmission range test is to determine whether the range of our Hive Node is sufficient to transmit data from our client’s hive to his home.

Results:

Preliminary range tests outside of Salazar Hall under ideal circumstances suggested a maximum transmission range of around 250 feet (75 m). Our client’s hive is located 220 feet from his router; thus, the group assumed our range was sufficient. Testing the transmission range on our client’s property in adverse conditions (hard rain), our range was deemed insufficient for our client’s needs and required revisitation; more range was required. To accomplish this, the group decided to incorporate a relay node to intercept packets outbound from the Hive Node and forward them to the Home Module, effectively doubling the system’s range. This test is in progress until the relay node is completed and its range is verified.

Figure 29: Home Module setup in clients home
Figure 30: Portable hive node setup for transmission test State of

Function Test 4: Transmission Range Test without relay (April 16, 2024)

Results:

After sampling a 432 Hz tone, the hive node successfully transmitted all 10240 ADC values. The home module successfully generated and uploaded the FFT with the expected spike at 432 Hz.

Figure 31: Range test generated spectrum

Function Test 5: Transmission Range Test with relay

Results:

After sampling a 432 Hz tone at the Hive Node, the Relay module successfully relayed the 10240 ADC values to the Home module. The expected frequency spectrum was generated and uploaded.

Function Test 6: IP55 Compliance Test

Results:

After spraying the IP55 container with garden hose with moderate pressure for 5 consecutive minutes followed by letting the housing sit for 10 minutes with the moisture strips inside, the test was ruled as a pass since none of the four moisture strips within reacted to the presence of water.

Figure 32: Relay Range test generated spectrum
Figure 33: IP55 container with moister strips

State of Test: PASS

System Test 1: Wireless Transmission

Objective:

The objective of the wireless transmission test is to determine if audio samples are successfully reconstructed by the home module such that they are not distorted, and no essential information is lost.

Results:

When comparing the FFT plotted in MATLAB from the raw audio sample of a healthy bee colony to the FFT that was produced on the home-node after the same data was wirelessly transmitted and reconstructed, their root mean square error was approximately 0.0489. This indicates a very low average difference between the spectrum plots.

System Test 2: Power Delivery Under Pressure

Results:

Figure 34: Pre and post transmission frequency spectrums
State of Test: PASS

This test to ensure power delivery under pressure was ruled as a pass. The FFC power delivery to the ESP was sustained for 3 hours at 82lbs of constant pressure. This shows that our means of getting power from outside of the hive to the inside of the hive without damaging the apiary is viable.

State of Test: PASS

System Test 3: Preventing Comb & Propolis Accumulation on Smart-Frame

Results:

After two months of storing the wire mesh protected frame in a very active hive and seeing little to know comb and propolis accumulation, the group confidently ruled this test as a pass. This shows that our means of protecting our sensors inside the hive is viable.

State of Test: PASS

Figure 35: Wire mesh frame after two months

References

[1] - Chauzat, Marie-Pierre, et al. “A case control study and a survey on mortalities of Honey Bee Colonies (apis mellifera) in France during the winter of 2005–6.” Journal of Apicultural Research, vol. 49, no. 1, 2010, pp. 40–51, https://doi.org/10.3896/ibra.1.49.1.06. mellifera) in France during the winter of 2005–6

[2] - Team, The Bee Informed. “United States Honey Bee Colony Losses 2020-2021: Preliminary Results.” Bee Informed Partnership, 23 June 2021, beeinformed.org/2021/06/21/united-states-honey-bee-colony-losses-2020-2021preliminary-results/.

[3] - Martin, Stephen J., et al. “Global honey bee viral landscape altered by a parasitic mite.” Science, vol. 336, no. 6086, 2012, pp. 1304–1306, https://doi.org/10.1126/science.1220941.

[4] - Entomology Today. “This Old Bee House: Study Deems Hive Boxes Drafty, Inefficient.” Entomology Today, 25 May 2021, entomologytoday.org/2021/04/16/honey-bee-hive-boxesdrafty-inefficient-temperature/.

[5]- https://apisprotect.com/

[6] - https://broodminder.com/

[7] - https://www.beescanning.com/

[8] ESP Zigbee SDK Programming Guide, https://docs.espressif.com/projects/esp-zigbeesdk/en/latest/esp32/index.html#esp-zigbee-sdk-programming-guide (accessed Nov. 5, 2023).

[9] “Hobbyiot Net,” HobbyIoT, https://www.hobbyiot.net/projects/hobbyiot-net (accessed Nov. 5, 2023).

[10] “Acoustic analysis of bee behavior – part 2,” Bee Hacker, https://www.beehacker.com/wp/?page_id=189 (accessed Nov. 5, 2023).

[11] “Acoustic analysis of bee behavior – part 1,” Bee Hacker, https://www.beehacker.com/wp/?page_id=103 (accessed Nov. 5, 2023).

[12] A. Dsouza, A. P, and S. Hegde, arXiv, rep., Nov. 2023

Appendix A

A.1 RELEASE OF LIABILTY

Product Providers

Apiary Assistant:

Gabe Esquibel, Josh Farrell, Giancarlo Succi

Undergraduate Program Seniors

Sonoma State University Department of Engineering

Client/Product Holder

George Ellison

Hobbyist Beekeeper

Sonoma County Beekeepers Association

Recitals

Within this agreement, the Product Providers are Sonoma State University students engaging in the installation of low voltage, low current, electrical equipment housed in a honey-frame-sized suite that will reside inside of, monitor internal conditions of, and record audio of, one or multiple beehives owned by the Client/Product Holder George Ellision.

Within this agreement, both parties acknowledge the inherent risks associated with placing this electrical equipment within the beehive. These risks include, but are not limited to bee loss, queen death, colony collapse, and potential physical damage to the hive structure. In addition to the potential risks that the hive faces, both parties also agree that any damage to the equipment provided by the Product Providers is possible, and that the Product Holder will not be liable for malfunction, weathering, or any colony impact to the framesuite or external power and transmission housing.

Therefore, in consideration of the mutual promises within the agreement, both parties agree to the following:

Release and Waiver

Product Providers hereby release liability for risks the hive faces that are associated with installation, maintenance, and storage of electrical equipment within the beehives such as bee loss, queen death, colony collapse, stunted honey production, or any other issues that may arise due to equipment placement, readjustment or presence of the product/equipment.

Product Holder hereby releases liability for risks that the product faces that are associated with installing, maintaining, storing, or working in the vicinity of the product, such as weathering, short circuiting, water damage, accidental damage, or bee-induced malfunction.

Assumption of Risk

Both parties acknowledge the risks associated with the installation, maintenance, and storage of either the product or the beehive including those that are known and those that cannot be foreseen. The Product Providers understand that the Product Holder may conduct routine work with their hive and are not to be held responsible for any wrongdoing to the product as a result. The Product Holder too understands that the Providers may occasionally need to conduct work on the Product onsite and will not be held responsible for any wrongdoing to the hive as a result.

The risk of aggravating the bees resulting in a swarm and excessive stinging during an attack is also an ever present risk and should always be regarded as a possibility. Due to the product holder and the product providers possibly posing a threat to the fragile colony, the bees might attack. WIth this possibility in mind, all persons interacting with the hive during any lengthy or intrusive maintenance should be well equipped with proper beekeeping PPE. Keeping an Epi-pen on hand for these reasons is strongly encouraged.

Care and Maintenance

Both parties agree to exercise the utmost caution when working either separately or together to test the equipment being installed, maintained and stored on, inside, or around

the product and hives. Both parties will make reasonable efforts to maintain the integrity of the product and the hives associated with it and to minimize potential damage to both. The Product providers shall have access to the product at request and upon product holders approval and may only work on, near, or within the hive when the product holder is present. Product providers will not be permitted to access hives without the product holders supervision. Whenever the Product holder sees a need to open the hive for investigation, the Product holder shall notify the Product providers that their equipment is being investigated in addition to the hive and will report any and all observations. During the time of investigation of the hive in which electrical equipment is installed, the Product Providers will have an open invitation to observe onsite along with the Product Holder’s investigation.

In the case that the product providers need to access the site of the hives, access will be permitted to that area of the product holder’s property so long written allowance has been given by the product holder and given that weather permits the entry into the hive requiring a minimum temperature of 67 degrees Fahrenheit for the day of entry. In addition, when inspection or work is conducted by the product providers, a minimum of two providers must be present. In the event that the product holder is not available to supervise the maintenance or inspection of product, then product providers must have specific written approval for access to facilities, utilities, or equipment.

Indemnification

Since no parties are liable for damage to the other's personal property, neither party will be obligated to compensate the other for any such loss or damage. If loss or damage occurs to either the hive or electrical equipment, both pastries will be notified as soon as damage is observed, and precautions will be taken to prevent further fault.

Duration and Termination

This contract is open to termination at any time through written confirmation and shall only be terminated after at least one signature is collected from both parties. If either party plans to terminate the agreement, there must be a prior notification of at least seven days in advance prior to official termination. In addition, prior to official termination of the agreement, equipment shall be removed from the hive and all personal property must be returned to their rightful owners.

*Signatures were collected from all parties

A.2 Project Code

A.2.1 Hive Node Code

Platformio.ini

; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html

[env:esp32doit-devkit-v1] platform = espressif32 board = esp32doit-devkit-v1 framework = arduino monitor_speed = 115200 lib_deps = robtillaart/DHT20@^0.3.1 olikraus/U8g2@^2.35.8 adafruit/RTClib@^2.1.3

HiveNode_Main.cpp

#include <SPI.h> #include <mrf24j.h> #include <Arduino.h> #include <Wire.h> #include <DHT20.h> #include <RTClib.h> // Include the RTClib library for DS3231 LINK: https://github.com/adafruit/RTClib/blob/master/examples/DS3231_alarm/DS3231_alarm.ino #include <Preferences.h> // Include the Preferences library for non-volatile storage #include <esp_sleep.h>

//#include <U8g2lib.h> //U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // INITIALIZE RTC PINS AND VARS RTC_DS3231 rtc; // Create an RTC DS3231 object RTC_I2C rtC(); // the pin that is connected to SQW #define CLOCK_INTERRUPT_PIN 32 int sample_counter = 0;

// INITIALIZE PINS FOR MRF TX/RX

#define pin_reset GPIO_NUM_15

#define pin_cs GPIO_NUM_4

#define pin_interrupt GPIO_NUM_13

Mrf24j mrf(pin_reset, pin_cs, pin_interrupt); const int MRF_turnOn = 2; //pin D2

// INITIALIZE VARIABLES FOR DHT20 AND BOTH TMP35

DHT20 DHT(&Wire1); //I2C interface

const int TMP1pin = 34; //const int TMP1pin = 27; ADC cHannel 2 const int TMP2pin = 35; float Vin = 3.31; // Declare global variables for CONDITIONS float HumidityAvg; float Temp1Avg; float Temp2Avg;

// INITIALIZE VARIABLES FOR MICROPHONE

const int adcPin = 36; // GPIO 36 corresponds to adc1_0 on ESP32 const int buttonPin = 5; // Change this to the GPIO pin where the button is connected const int numSamplesPerSecond = 2048; const int numSeconds = 5; const int numSamples = numSamplesPerSecond * numSeconds; const int bufferSize = 512; uint16_t audioBuffer[bufferSize]; uint16_t audio[numSamples]; int ack_count; int numbersPerLine; int tx_failed_count; int sendCount; int retransmitions = 0;

// MRF VARIABLES AND COUNTERS long last_time; long tx_interval = 250; int count = 0; int owo = 0;

// BEGIN FUNCTION DECLARATIONS

//(1)

String addLeadingZeroes(String value) { // Read the analog value // Convert the value to a String and add leading zeroes while (value.length() < 4) { value = "0" + value; } return value; }

//(2)

void sample_audio() { Serial.println("Sampling Audio..."); unsigned long startTime = micros(); // Record start time //SAMPLE AUDIO for (int i = 0; i < numSamples; i++) { audio[i] = analogRead(adcPin); delayMicroseconds(1000000 / numSamplesPerSecond); // Delay to achieve the desired sampling rate } // Record end time and elapsed time unsigned long endTime = micros();

float elapsedTime = (endTime - startTime)/(1000000.00);

//Print how long the 5 second sample took to measure

Serial.println("DONE....");

Serial.println("Sampling time:");

Serial.print(elapsedTime);

Serial.println(" Seconds");

//print how many values were saved into the array

Serial.print("Size of Audio Array: "); Serial.println(sizeof(audio) / sizeof(audio[0])); } //END void audio_sample

//(3)

float sampleAndAverageHumidity() { float humiditySum = 0; for (int i = 0; i < 1; i++) { //get 10 humidity readings DHT.read(); //read i2c humiditySum += DHT.getHumidity(); //get humidity reading delay(20); } float avgHumidity = humiditySum / 1; //divide sum of readings by number of readings return avgHumidity; }

//(4) PENDING ADC ERROR

float sampleTMP1() { float temp1Sum = 0; for (int i = 0; i < 1; i++) { int raw1 = analogRead(TMP1pin); //Serial.println(raw1); //check for correctness float Vo1 = ( float(raw1) * (Vin/float(4095)) ) + 0.104; //the PLUS 0.129 is adding the voltage floor the the volateg output //Serial.println(Vo1,3); //check for correctness temp1Sum += ( (((102.76*(Vo1)) - 0.9965)*(1.8)) + 32 ); delay(20); } float avgTemp1 = temp1Sum/1; return avgTemp1; }

//(5)

float sampleTMP2() { int temp2Sum = 0; for (int i = 0; i < 1; i++) { int raw2 = analogRead(TMP2pin); //Serial.println(raw2); //check for correctness float Vo2 = (Vin * (float(raw2)/(float(4095))) ) + 0.111; //swapped Vin and float(raw2) in the equation //Serial.println(Vo2,2); //check for correctness temp2Sum += ( (((102.76*(Vo2)) - 0.9965)*(1.8)) + 32 ); delay(20); } int avgTemp2 = temp2Sum / 1; return avgTemp2; }

//(6)

void interrupt_routine() { mrf.interrupt_handler(); // mrf24 object interrupt routine }

//(7)

void handle_rx() {

Serial.print("received a packet ");Serial.print(mrf.get_rxinfo()->frame_length, DEC);Serial.println(" bytes long");

if(mrf.get_bufferPHY()){

Serial.println("Packet data (PHY Payload):"); for (int i = 0; i < mrf.get_rxinfo()->frame_length; i++) { Serial.print(mrf.get_rxbuf()[i]); } }

Serial.println("\r\nASCII data (relevant data):"); for (int i = 0; i < mrf.rx_datalength(); i++) { Serial.write(mrf.get_rxinfo()->rx_data[i]); }

Serial.print("\r\nLQI/RSSI="); Serial.print(mrf.get_rxinfo()->lqi, DEC); Serial.print("/");

Serial.println(mrf.get_rxinfo()->rssi, DEC); }

//(8)

void handle_tx() { if (mrf.get_txinfo()->tx_ok) { //Serial.println("TX went ok, got ack"); ack_count++; }

else { tx_failed_count++; Serial.print("TX failed after "); Serial.print(mrf.get_txinfo()->retries); Serial.println(" retries\n");

} }

//(9)

void retransmit(char* data) { Serial.println("Attempting retransmission..."); mrf.send16(0x4202, data); mrf.check_flags(&handle_rx, &handle_tx); retransmitions++; }

//(10)

void sampleAndSendAudio() { numbersPerLine = 0; sendCount = 0; ack_count = 0; tx_failed_count = 0; retransmitions = 0;

Serial.println(""); Serial.println(" AUDIO "); Serial.println(" "); //SAMPLE AUDIO sample_audio(); Serial.println(" ");

/* // THIS SENDS THE DATA PROMPT char * Audio_Start = "RX Audio"; mrf.send16(0x4202, Audio_Start); //THIS SENDS THE DATA PROMPT

mrf.check_flags(&handle_rx, &handle_tx); while(!(mrf.get_txinfo()->tx_ok)) { Serial.println("Attempting retransmission..."); retransmit(Audio_Start); //call retransmit function mrf.check_flags(&handle_rx, &handle_tx); delay(50); } //*/

unsigned long startTime2 = micros(); //begin Transmission session timer

// CONVERTS Array into chunks of four numbers that can be transmitted from MRF to MRF transceivers

String sample_chunk = ""; //Serial.println(" Printing in groups of 4 "); // Print up to 4 numbers per line for (int i = 0; i < numSamples; i++) { sample_chunk += addLeadingZeroes(String(audio[i])); // OR USE: "sample_chunk += String(audio[i]);"" for no leading zeroes sample_chunk += ",";

// Check if we've reached 4 numbers if (++numbersPerLine >= 4) { //Serial.println(myCharArray); //sample_chunk += "/e"; //terminate chuck with delimitter char* myCharArray = strdup(sample_chunk.c_str()); // Convert sample_chunk String to const char* //Serial.println(myCharArray); //prints one group of 4 ADC vals

//if (current_time - last_time > tx_interval) { //??? refer to second line in void loop() //last_time = current_time; //Serial.println("txxxing...");

//SEND AND RETRANSMIT IF NO ACKNOWLEGMENT IS RECEIVED mrf.send16(0x4202, myCharArray); mrf.check_flags(&handle_rx, &handle_tx); //handle_tx(); //delay(100); while(!(mrf.get_txinfo()->tx_ok)) { retransmit(myCharArray); //call retransmit function delay(50); }

mrf.check_flags(&handle_rx, &handle_tx);

//Serial.println(myCharArray); delay(50); //}

sample_chunk = ""; // Reset the string for the next line numbersPerLine = 0; // Reset the count } }

// If there are remaining numbers, print them if (numbersPerLine > 0)

{ Serial.print("Extra nums:"); //ther should not be any remainders, 10240/4 = 2560

Serial.println(sample_chunk); }

Serial.println("");

Serial.println("");

unsigned long endTime2 = micros(); //end Transmission session timer float elapsedTime2 = (endTime2 - startTime2)/(1000000.00);

Serial.println("....AUDIO TX RESULTS....");

Serial.print("Elapsed TX Time: "); Serial.print(elapsedTime2);

Serial.println(" Seconds");

Serial.print("Retransmitions: "); Serial.println(retransmitions); Serial.print("Acknowledgements: ");

Serial.println(ack_count);

Serial.print("Lost TXs: "); Serial.println(tx_failed_count);

}

//(11)

void SampleTempAndHum() { HumidityAvg = sampleAndAverageHumidity(); //call sample&avg function Temp1Avg = sampleTMP1(); Temp2Avg = sampleTMP2();

Serial.println("");

Serial.println("TEMPERATURES AND HUMIDITY"); Serial.println(" ");

Serial.print("TMP 1 Temp: ");

Serial.print(Temp1Avg,0); Serial.println(" F");

Serial.print("TMP 2 Temp: "); Serial.print(Temp2Avg,0);

Serial.println(" F");

Serial.print("DHT20 Humidity: "); Serial.print(HumidityAvg,0);

Serial.println(" %"); Serial.println(" "); Serial.println(""); delay(200); }

//(12)

void SampleAndSend_TempHum() { SampleTempAndHum();

String Conditions_packet = "COND ";

String Temp1String = String(Temp1Avg, 0); String Temp2String = String(Temp2Avg, 0); String HumidityString = String(HumidityAvg,0);

// Construct the conditions packet

Conditions_packet += HumidityString; Conditions_packet += ","; Conditions_packet += Temp1String; Conditions_packet += ","; Conditions_packet += Temp2String;

char* myCharArray2 = strdup(Conditions_packet.c_str()); Serial.println(myCharArray2);

//SEND AND RETRANSMIT IF NO ACKNOWLEGMENT IS RECEIVED mrf.send16(0x4202, myCharArray2); mrf.check_flags(&handle_rx, &handle_tx); //handle_tx(); //delay(100); while(!(mrf.get_txinfo()->tx_ok)) { retransmit(myCharArray2); //call retransmit function delay(50); } mrf.check_flags(&handle_rx, &handle_tx);

//Serial.println(myCharArray2); delay(50); }

//(13)

void Check_RTC_time() {

DateTime now = rtc.now(); // Get current date and time from RTC // Concatenate date components into a single string

String time = String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second());

String date = String(now.year()) + "/" + String(now.month()) + "/" + String(now.day()); Serial.println("Current Time: " + time); Serial.println("Current Date: " + date); }

//(14)

void onAlarm() { Serial.println("Alarm occurred FROM FUNCTION!"); Serial.println("Going back to Sleep..."); delay(1500); // After the alarm, go to deep sleep esp_deep_sleep_start(); }

// END FUNCTION DECLARATIONS

void setup() {

Serial.begin(115200); analogReadResolution(12); // Set ADC resolution to 12 bits (0-4095) pinMode(pin_reset, OUTPUT); // MRF GPIO pinMode(buttonPin, INPUT); // Assuming the other side of the button is connected to GND

pinMode(adcPin, INPUT); pinMode(TMP1pin, INPUT); pinMode(TMP2pin, INPUT); pinMode(MRF_turnOn, OUTPUT); digitalWrite(MRF_turnOn, HIGH); //MUST TURN ON HIGH PIN BEFORE RUNNING SETUP Wire1.begin(21, 22); // EPS32 Devkit pin numbers (SDA, SCL) rtc.begin(); SPI.begin(); mrf.reset(); mrf.init(); //digitalWrite(MRF_turnOn, HIGH); mrf.set_pan(0xcafe); //set address abd print it mrf.address16_write(0x6001); Serial.println(""); Serial.println("");

Serial.println(""); Serial.println("Network: 0xcafe ............ Address: 0x6001"); delay(50); attachInterrupt(pin_interrupt, interrupt_routine, CHANGE); // interrupt 0 equivalent to pin 2(INT0) on ATmega8/168/328 last_time = millis(); interrupts(); delay(50);

//RTC SET-UP CODE

// if (!rtc.begin()) { // Initialize the RTC object Serial.println("Couldn't find RTC"); while (1); } if (rtc.lostPower()) { // If the RTC lost power, set the time to the time of sketch compilation Serial.println("RTC lost power, let's set the time!"); rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); }

//we don't need the 32K Pin, disable it rtc.disable32K();

// Making it so, that the alarm will trigger an interrupt pinMode(CLOCK_INTERRUPT_PIN, INPUT_PULLUP); //attachInterrupt(CLOCK_INTERRUPT_PIN, onAlarm, FALLING); attachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN), onAlarm, FALLING); esp_sleep_enable_ext0_wakeup((gpio_num_t)CLOCK_INTERRUPT_PIN, 0); // Trigger on low level

// stop oscillating signals at SQW Pin rtc.writeSqwPinMode(DS3231_OFF);

// set alarm 1, 2 flag to false (so alarm 1, 2 didn't happen so far) // if not done, this easily leads to problems, as both register aren't reset on reboot/recompile rtc.clearAlarm(1); rtc.clearAlarm(2);

// stop oscillating signals at SQW Pin // otherwise setAlarm1 will fail rtc.writeSqwPinMode(DS3231_OFF);

// turn off alarm 2 (in case it isn't off already) // again, this isn't done at reboot, so a previously set alarm could easily go overlooked rtc.disableAlarm(2);

// Set the RTC time MANUALLY ONLY IF IT NEED ADJUSTMENT

//DateTime rtcTime(2024, 3, 26, 14, 23, 00); // Format: (year, month, day, hour, minute, second) //rtc.adjust(rtcTime);

DateTime now = rtc.now(); //DateTime alarmTime(now.year(), now.month(), now.day(), now.hour(), now.minute()+1, now.second());

DateTime alarmTime = now + TimeSpan(0, 1, 0, 0); //SET TIMER HERE!

// Set the alarm if (!rtc.setAlarm1(alarmTime, DS3231_A1_Minute)) {

Serial.println("Error, alarm wasn't set!"); } else { Serial.println("");

Serial.println("Alarm set successfully!"); Serial.println(" "); }

// Read the counter value from non-volatile storage Preferences preferences; preferences.begin("settings", false); sample_counter = preferences.getInt("counter", 0); preferences.end(); //END RTC SET-UP CODE delay(1000);

// uncomment if you want to receive any packet on this channel //mrf.set_promiscuous(true); // uncomment if you want to enable PA/LNA external control //mrf.set_palna(true); // uncomment if you want to buffer all PHY Payload //mrf.set_bufferPHY(true); } void loop() {

Serial.println("ESP32 IS AWAKE!"); Serial.println(" "); Check_RTC_time(); DHT.begin();

mrf.check_flags(&handle_rx, &handle_tx); unsigned long current_time = millis();

//INCRIMENT COUNTER

if(sample_counter >=5){ sample_counter=0; } sample_counter++; Serial.print("Sample Counter = "); Serial.print(sample_counter); // Store the counter value in non-volatile storage Preferences preferences; preferences.begin("settings", false); preferences.putInt("counter", sample_counter); preferences.end(); delay(100);

for(int i = 0; i<3; i++) { Serial.print("."); delay(80); }

Serial.println("."); Serial.println(" "); delay(400);

if(sample_counter == 1 || sample_counter == 2 || sample_counter == 3 || sample_counter == 4) { DHT.begin(); SampleAndSend_TempHum();

if(sample_counter == 4) { sample_counter = 0; Serial.print("Sample Counter RESET to: "); Serial.println(sample_counter); // Store the counter value in non-volatile storage Preferences preferences; preferences.begin("settings", false); preferences.putInt("counter", sample_counter); preferences.end(); } } delay(10000);

if(sample_counter == 1)//CHANGE back to 1 { Serial.println(""); detachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN)); digitalWrite(CLOCK_INTERRUPT_PIN,HIGH); delay(20); sampleAndSendAudio(); delay(200); } rtc.begin(); delay(10);

DateTime alarm1 = rtc.getAlarm1(); char alarm1Time[10] = "hh:mm:ss"; alarm1.toString(alarm1Time); Serial.print("New Wake Alarm Set to: "); Serial.println(alarm1Time);

if (digitalRead(buttonPin) == HIGH) { detachInterrupt(digitalPinToInterrupt(CLOCK_INTERRUPT_PIN)); DHT.begin(); digitalWrite(CLOCK_INTERRUPT_PIN,HIGH); sampleAndSendAudio(); }

Serial.print("Entering deep sleep"); delay(500); Serial.print("."); delay(500); Serial.print("."); delay(500); Serial.print("."); delay(500); Serial.println(""); Serial.println(""); Serial.println(""); Serial.println(""); digitalWrite(MRF_turnOn, LOW); esp_deep_sleep_start();

A.2.2 Home Module Code (ESP32)

Platformio.ini

; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html

[env:esp32doit-devkit-v1] platform = espressif32 board = esp32doit-devkit-v1 framework = arduino monitor_speed = 115200

Home_Module_v1.cpp

#include <SPI.h>

#include <mrf24j.h>

#include <Arduino.h>

#include <Wire.h>

#define I2C_Slave_Address 0x69

//const int pin_reset = 21; //clock on esp32

#define pin_reset GPIO_NUM_15

//const int pin_cs = 25; //xtal on esp32

#define pin_cs GPIO_NUM_4

//const int pin_interrupt = 19; #define pin_interrupt GPIO_NUM_13

Mrf24j mrf(pin_reset, pin_cs, pin_interrupt);

long last_time; long tx_interval = 5000;

byte val = 0;

char array_rx[10240]; //int receive_counter;

//send recieved data over I2C void requestEvent() { Wire.write(array_rx); }

void interrupt_routine() { mrf.interrupt_handler(); // mrf24 object interrupt routine }

void handle_rx() { //receive_counter++; Serial.print("received a packet "); Serial.print(mrf.get_rxinfo()->frame_length, DEC); Serial.println(" bytes long");

if(mrf.get_bufferPHY()) { Serial.println("Packet data (PHY Payload):"); for (int i = 0; i < mrf.get_rxinfo()->frame_length; i++) { Serial.print(mrf.get_rxbuf()[i]); } }

/*

Serial.println("\r\nASCII data (relevant data):"); */ for (int i = 0; i < mrf.rx_datalength(); i++) { Serial.write(mrf.get_rxinfo()->rx_data[i]); array_rx[i] = mrf.get_rxinfo()->rx_data[i]; //Serial.println(array_rx[i]); }

/* Serial.print("\r\nLQI/RSSI="); Serial.print(mrf.get_rxinfo()->lqi, DEC); Serial.print("/"); Serial.println(mrf.get_rxinfo()->rssi, DEC); */

Serial.println(" "); Serial.println("Received Data: "); Serial.println(array_rx); Serial.println(" ");

digitalWrite(32, HIGH); delay(10); digitalWrite(32, LOW); }

void handle_tx() { if (mrf.get_txinfo()->tx_ok) { Serial.println("TX went ok, got ack"); } else {

Serial.print("TX failed after "); Serial.print(mrf.get_txinfo()->retries); Serial.println(" retries\n"); } }

void setup() { Serial.begin(115200); pinMode(pin_reset, OUTPUT); pinMode(32, OUTPUT); digitalWrite(32, LOW);

delay(2000); SPI.begin(); mrf.reset(); mrf.init();

receive_counter;

Wire.begin(I2C_Slave_Address); Wire.onRequest(requestEvent);

Serial.println(" "); Serial.println("Initialized as I2C Slave");

mrf.set_pan(0xcafe);

// This is _our_ address Serial.println(" ");

Serial.println("Network: 0xcafe"); mrf.address16_write(0x4202);

Serial.println("Address: 0x4202");

// uncomment if you want to receive any packet on this channel //mrf.set_promiscuous(true);

// uncomment if you want to enable PA/LNA external control //mrf.set_palna(true);

// uncomment if you want to buffer all PHY Payload //mrf.set_bufferPHY(true);

attachInterrupt(pin_interrupt, interrupt_routine, CHANGE); // interrupt 0 equivalent to pin 2(INT0) on ATmega8/168/328 last_time = millis(); interrupts(); }

void loop() { mrf.check_flags(&handle_rx, &handle_tx);

//if (receive_counter > 2550) { //Serial.print(receive_counter); //Serial.println(" Transmissions Recieved"); //Serial.println(" "); //} }

A.2.3 Home Module Code (Raspberry Pi)

I2C.py

#!/usr/bin/env python import smbus import time

import RPi.GPIO as GPIO import os import subprocess import sys

GPIO.setmode(GPIO.BCM); GPIO.setup(17, GPIO.IN);

# Define the I2C address to listen for address = 0x69

# Create an I2C bus object bus = smbus.SMBus(1) # Use 1 for Raspberry Pi Model B

# Create transmission counter write_counter = 0

I2C_counter = 0

x = 0

global start start = time.time()

def split_numbers(input_string): if len(input_string) > 20: #COMMENTED OUT TO TEST PACKET ENUMERATION return input_string[:20] #COMMENTED OUT TO TEST PACKET ENUMERATION # if len(input_string)>20: #ADDED IN TO TEST PACKET ENUMERATION # return input_string[:24] #ADDED IN TO TEST PACKET ENUMERATION

else: return input_string

def write_to_file(file_path, text): try:

with open(file_path, 'a') as file: file.write(text) global write_counter write_counter = write_counter + 1

except IOError: print("IOError")

def receive_integer(): try:

data = bus.read_byte(address) data = bus.read_i2c_block_data(address,0,32) received_message = "".join([chr(byte) for byte in data if byte !=0]) delimited_message = split_numbers(received_message) delimited_message = delimited_message + "\n" write_to_file("values.txt", delimited_message)

except Exception as e: print("I HATE YOU I HATE YOU", str(e)) print("Time since last epoch:") print(start) print("") print("Listening for tx...") while True: if (GPIO.input(17)): start = time.time() receive_integer() time.sleep(0.0251) x = 1

end = time.time()

elapsed = end - start if(elapsed >= 30 and x == 1): print("30 seconds since last packet")

os.system("./MP3.py")

os.system("sudo rm values.txt") os.system("touch values.txt") os.system("./db_upload.py") x = 0 print("")

print("Listening for tx...")

MP3.py

#!/usr/bin/env python import smbus import time import RPi.GPIO as GPIO import os import subprocess import sys

GPIO.setmode(GPIO.BCM); GPIO.setup(17, GPIO.IN);

# Define the I2C address to listen for address = 0x69

# Create an I2C bus object bus = smbus.SMBus(1) # Use 1 for Raspberry Pi Model B

# Create transmission counter

write_counter = 0

I2C_counter = 0

x = 0

global start start = time.time()

def split_numbers(input_string): if len(input_string) > 20: #COMMENTED OUT TO TEST PACKET ENUMERATION return input_string[:20] #COMMENTED OUT TO TEST PACKET ENUMERATION # if len(input_string)>20: #ADDED IN TO TEST PACKET ENUMERATION # return input_string[:24] #ADDED IN TO TEST PACKET ENUMERATION

else:

return input_string

def write_to_file(file_path, text): try: with open(file_path, 'a') as file: file.write(text) global write_counter write_counter = write_counter + 1

except IOError: print("IOError")

def receive_integer(): try:

data = bus.read_byte(address) data = bus.read_i2c_block_data(address,0,32) received_message = "".join([chr(byte) for byte in data if byte !=0]) delimited_message = split_numbers(received_message) delimited_message = delimited_message + "\n" write_to_file("values.txt", delimited_message)

except Exception as e: print("I HATE YOU I HATE YOU", str(e))

print("Time since last epoch:") print(start)

print("")

print("Listening for tx...") while True: if (GPIO.input(17)): start = time.time() receive_integer() time.sleep(0.0251) x = 1

end = time.time() elapsed = end - start if(elapsed >= 30 and x == 1): print("30 seconds since last packet") os.system("./MP3.py") os.system("sudo rm values.txt") os.system("touch values.txt") os.system("./db_upload.py") x = 0

print("")

print("Listening for tx...")

db_upload.py

#!/usr/bin/env python import subprocess import datetime import mysql.connector import os

config = { 'host':'195.179.236.205', 'database':'u396706841_DataStorage ', 'user':'u396706841_PicMen ', 'password':'PICMen707' }

audio_path = "/home/gcsucci/bee_sounds.mp3"

image_path = "/home/gcsucci/Bee_audio.png"

current_datetime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

print("")

print("Connecting to database...")

try:

print("0") connection = mysql.connector.connect(**config) print("1") cursor = connection.cursor() print("2")

with open(audio_path, 'rb') as file: audio_data = file.read() with open(image_path, 'rb') as file: image_data = file.read()

query = "INSERT INTO audio_table (bee_audio, FFT_image, current_datetime) VALUES (%s,%s,%s)" insert_data = (audio_data, image_data, current_datetime) cursor.execute(query, insert_data) connection.commit()

print("Audio and FFT uploaded") except Exception as e:

print(f"connection failed: {e}")

temp_hum_upload.py

#!/usr/bin/env python

import subprocess import datetime import mysql.connector import os

config = { 'host':'195.179.236.205', 'database':'u396706841_DataStorage ', 'user':'u396706841_PicMen ', 'password':'PICMen707' }

file_path = "/home/gcsucci/values.txt"

current_datetime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

print("")

print("Connecting to database...")

try:

print("0") connection = mysql.connector.connect(**config) print("1")

cursor = connection.cursor() print("2")

with open(file_path, 'r') as file: content = file.read()

numbers = [int(number) for number in content.split(",")] number1, number2, number3 = numbers

print("Humidity: ",number1)

print("Temperatures: ",number2, number3)

query = "INSERT INTO temp_hum (humidity, temp_1, temp_2, current_datetime) VALUES (%s,%s,%s,%s)" insert_data = (number1, number2, number3, current_datetime) cursor.execute(query, insert_data) connection.commit()

print("temperature and humidity uploaded") except Exception as e:

print(f"connection failed: {e}")

A.2.4 Relay Node Code

Platformoi.ini

; PlatformIO Project Configuration File ;

; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html

[env:esp32doit-devkit-v1] platform = espressif32 board = esp32doit-devkit-v1 framework = arduino monitor_speed = 115200 lib_deps = robtillaart/DHT20@^0.3.1 olikraus/U8g2@^2.35.8 adafruit/RTClib@^2.1.3 monitor_filters = direct, log2file

Relay_Module.cpp

#include <SPI.h>

#include <mrf24j.h>

#include <Arduino.h>

#include <Wire.h>

#include <RTClib.h> // Include the RTClib library for DS3231 LINK: https://github.com/adafruit/RTClib/blob/master/examples/DS323 1_alarm/DS3231_alarm.ino

#include <Preferences.h> // Include the Preferences library for non-volatile storage #include <esp_sleep.h>

//#include <U8g2lib.h> //U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

char array_rx[10240]; // recieved audio array, only one packet per row String transmission_array[2560]; // recieved array, 4 packets per row

String data; int a; int x; unsigned long current_time; unsigned long last_time; unsigned long elapsed_time;

// INITIALIZE RTC PINS AND VARS

RTC_DS3231 rtc; // Create an RTC DS3231 object RTC_I2C rtC(); // the pin that is connected to SQW #define CLOCK_INTERRUPT_PIN 32 int sample_counter = 0; int receive_counter;

// INITIALIZE PINS FOR MRF TX/RX #define pin_reset GPIO_NUM_15 #define pin_cs GPIO_NUM_4 #define pin_interrupt GPIO_NUM_13 Mrf24j mrf(pin_reset, pin_cs, pin_interrupt); const int MRF_turnOn = 2; //pin D2

int ack_count; int numbersPerLine; int tx_failed_count;

int sendCount; int retransmitions = 0;

// MRF VARIABLES AND COUNTERS

//long last_time; long tx_interval = 250; int count = 0; int owo = 0;

// BEGIN FUNCTION DECLARATIONS

//(1)

String addLeadingZeroes(String value) { // Read the analog value // Convert the value to a String and add leading zeroes while (value.length() < 4) { value = "0" + value; } return value; }

//(3)

void interrupt_routine() { mrf.interrupt_handler(); // mrf24 object interrupt routine }

//(4)

void handle_rx() {

x = 1;

last_time = current_time; //Serial.print("received a packet "); //Serial.print(mrf.get_rxinfo()->frame_length, DEC); //Serial.println(" bytes long:");

/* if(mrf.get_bufferPHY()) {

Serial.println("Packet data (PHY Payload):"); for (int i = 0; i < mrf.get_rxinfo()->frame_length; i++) { Serial.print(mrf.get_rxbuf()[i]); } } */

// save packet payload to array_rx for (int i = 0; i < mrf.rx_datalength(); i++) { Serial.write(mrf.get_rxinfo()->rx_data[i]); array_rx[i] = mrf get_rxinfo()->rx_data[i]; //Serial.println(array_rx[i]); } Serial println(" "); transmission_array[a] = array_rx; a++;

}

//(5)

void handle_tx() {

if (mrf get_txinfo()->tx_ok) { //Serial.println("TX went ok, got ack"); ack_count++; }

else { tx_failed_count++; //Serial.print("TX failed after "); //Serial.print(mrf.get_txinfo()->retries); //Serial.println(" retries\n"); } }

//(6)

void retransmit(char* data) {

Serial println("Attempting retransmission..."); mrf.send16(0x4202, data); mrf.check_flags(&handle_rx, &handle_tx); retransmitions++; }

//(7)

void Check_RTC_time() {

DateTime now = rtc.now(); // Get current date and time from RTC // Concatenate date components into a single string

String time = String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second());

String date = String(now year()) + "/" + String(now month()) + "/" + String(now day());

Serial println("Current Time: " + time);

Serial println("Current Date: " + date); }

//(8)

void onAlarm() {

Serial.println("Alarm occurred FROM FUNCTION!"); Serial println("Going back to Sleep..."); delay(1500); // After the alarm, go to deep sleep esp_deep_sleep_start(); }

// END FUNCTION DECLARATIONS

void setup() {

Serial.begin(115200); pinMode(pin_reset, OUTPUT); // MRF GPIO SPI.begin(); mrf.reset(); mrf init();

mrf set_pan(0xcafe); //set address abd print it mrf address16_write(0x4202); Serial.println(""); Serial.println(""); Serial.println(""); Serial.println("Network: 0xcafe"); Serial println("Address: 0x4202"); delay(50);

attachInterrupt(pin_interrupt, interrupt_routine, CHANGE); last_time = millis(); interrupts(); a = 0; x = 0; last_time = millis(); delay(1000);

// uncomment if you want to receive any packet on this channel //mrf.set_promiscuous(true);

// uncomment if you want to enable PA/LNA external control //mrf.set_palna(true); // uncomment if you want to buffer all PHY Payload //mrf.set_bufferPHY(true); }

void loop() { //mrf.check_flags(&handle_rx, &handle_tx);

//Serial.println("txxxing..."); //mrf.send16(0x4202, "Be not afraid."); //Serial.println("Listening..."); mrf.check_flags(&handle_rx, &handle_tx);

current_time = millis(); elapsed_time = current_time - last_time; //Serial.println(elapsed_time);

if (elapsed_time > 30000 && x == 1) {

Serial println(" "); last_time = current_time;

Serial.println("30 seconds since last packet"); Serial.println("Received packets:");

Serial.print(a); Serial println(" ");

for (int i = 0; i < a; i++) { Serial.println(transmission_array[i]); }

/*

Serial.println(" "); Serial.println("Transmiting data..."); Serial.println(" ");

for (int i = 0; i < a; i++) { //String packet = transmission_array[i]; char* packet = strdup(transmission_array[i].c_str()); Serial.print("Txxxing "); Serial.println(packet); mrf.send16(0x4202, packet); delay(50); mrf.check_flags(&handle_rx, &handle_tx); }

a = 0; x = 0;

Serial.println("Tx complete, back to listening..."); delay(10000); */ }

//VOID LOOP END }

A.2.5 Website PHP Code homepage.html

<!DOCTYPE html> <html>

<head>

<title>Apiary Assistant Homepage</title>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> <script> $( function() { $( "#start-datepicker" ).datepicker(); //Two datepickers for start and end.

$( "#end-datepicker" ).datepicker(); } );

</script>

</head> <body> <?php

$timezone = 'America/Los_Angeles';

$today = new DateTime('now', new DateTimeZone($timezone)); error_reporting(E_ALL);

//Error reporting because this code was not made in a day ini_set('display_errors', 1);

//$today = new DateTime(); //New instance of DateTime objects

$todaysDate = $today->format('Y-m-d'); //Format for parsing by SQL query

$startDate = $todaysDate . " 00:00:00";

//Webpage should only display today,s data, thus startDate = today at midnight

//$startDate = "2024-04-01" . " 00:00:00";

//For testing with all datapoints

$endDate = $todaysDate . " 23:59:59";

//Just before midnight today

$host = 'localhost';

//SQL parameters

$username = 'u396706841_PicMen'; $password = 'PICMen707'; $database = 'u396706841_DataStorage';

$conn = new mysqli($host, $username, $password, $database); //SQL query if ($conn->connect_error) {die("Connection failed: " . $conn->connect_error);}

$sql = "SELECT * FROM temp_hum WHERE current_datetime BETWEEN '$startDate' AND '$endDate'"; //Get temperature and humidity from table for ONLY TODAY

$result = $conn->query($sql);

$temp1 = [];

//Init empty array to hold temp1 values

$temp2 = []; //"" temp2

$hum = []; //"" humidity

$time = []; //"" timestamps

if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { $temp1[] = $row["temp_1"]; //Put table data in empty array $temp2[] = $row["temp_2"]; //""

$hum[] = $row["humidity"]; //""

$time[] = $row["current_datetime"]; //"" } }

$conn->close(); echo $todaysDate; ?>

<style>

form input[type="submit"]:hover { background-color: #0056b3; //Ooooh, user interaction! } body { background-image: url('https://cdn0.iconfinder.com/data/icons/animalswildlife-line-art-1/128/honeycomb-1024.png'), linear-gradient(to bottom, rgba(0,0,0,0.2), rgba(0,0,0,0.2)); background-repeat: repeat; background-size: cover; background-position: center center; color: gray; position: relative; }

form { text-align: center; }

h1 { text-align: center; font-size: 48; } h3 {text-align: center; font-size: 32; } </style>

<h1>Apiary Assistant Homepage</h1>

<br>

<h3>View Spectrums and Audio for Date Range:</h3> <form action="datapage.html"> <! Embed for reaching data query page > <input type="submit" value="Query by Date"> </form> <br><br>

<h3>Today's Temperature and Humidity Trend:</h3> <canvas id="myChart" width="800" height="400"></canvas> <script> // JavaScript code to render the chart var ctx = document.getElementById('myChart').getContext('2d'); //New chart var myChart = new Chart(ctx, { type: 'line', //Line chart data: { labels: <?php echo json_encode($time); ?>, //Label x-axis with time datasets: [{ label: 'Center Temperature (°F)', //subject to change

data: <?php echo json_encode($temp1); ?>, //Create .JSON for reading temp1 values

backgroundColor: 'rgba(255, 0, 0, 1)', //temp1 line is red

borderColor: 'rgba(255, 50, 50, 1)', borderWidth: 3

}, { label: 'Outer Temperature (°F)', //subject to change.

data: <?php echo json_encode($temp2); ?>, //Create .JSON for reading temp2 values

backgroundColor: 'rgba(0, 128, 128, 1)', //temp2 line is blue

borderColor: 'rgba(0, 128, 128, 1)', borderWidth: 3

}, { label: 'Humidity (%)', //Humidity graph

data: <?php echo json_encode($hum); ?>, //Create .JSON for reading humidity values

backgroundColor: 'rgba(0, 255, 0, 1)', //hum line is green

borderColor: 'rgba(50, 255, 50, 1)', borderWidth: 3 }]

}, options: { scales: { yAxes: [{ ticks: { beginAtZero: true //Start chart at x=0 } }] } } });

</script>

<br>

<h3>Input Specific Date Range for Temperature and Humidity: </h3> <form action = "temphum.php" method="POST" onsubmit = "return validateForm()"> <! POST to query page upon successful form validation > <label for="start-datepicker">Start Date: </label> <! Start the start datepicker. To do: Figure out how to stop autofill. Edge thinks I want to put my debit card number here. I do not. > <input type="text" name="sd" id = "start-datepicker"> <br> <label for="end-datepicker">End Date: </label> <! Start the end datepicker > <input type="text" name="ed" id = "end-datepicker">

<br> <br>

<input type="submit" value="Submit Dates" style="font-size: 24px; padding: 10px 20px;"> <! Submit button stylizing to appreciate that background color change > </form>

<script> function validateForm() { //Ensure all forms are filled out var sd = document.getElementById('start-datepicker').value; var ed = document.getElementById('end-datepicker').value;

if (sd === '' || ed === '') { //Nothing left blank, OR ELSE alert("Please fill in all date fields or we'll find you."); return false; } return true; } </script>

</body> </html>

datasearch.php

<!DOCTYPE html> <html> <head>

<title> Apiary Assistant Data View</title> </head> <body> <?php

$sd = $_POST["sd"]; $ed = $_POST["ed"]; $resd = date("Y-m-d", strtotime($sd)); $reed = date("Y-m-d", strtotime($ed)); $startdate = $resd; $enddate = $reed; //echo $startdate; //echo $enddate;

// Connect to database

$host = 'localhost';

$username = 'u396706841_PicMen';

$password = 'PICMen707';

$database = 'u396706841_DataStorage';

$conn = new mysqli($host, $username, $password, $database); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); }

//need another sql query //increment through resultant to display each day's data //

// SQL query to fetch data

$sql = "SELECT * FROM audio_table WHERE current_datetime BETWEEN '$startdate' AND '$enddate'";

$result = $conn->query($sql); while ($row = $result->fetch_assoc()) { if (!empty($row['FFT_image'])) { echo "<br>" . $row["current_datetime"]; echo '<br> ID: ' . $row["id"]; // Convert BLOB data to image and display $imageData = $row['FFT_image']; $image = imagecreatefromstring($imageData); if ($image !== false) {

// Display the image

echo '<img src="data:image/png;base64,' . base64_encode($imageData) . '" alt="FFT Image">';

// Free up memory imagedestroy($image); } else { echo "Invalid image data"; } } else { echo "No image available"; } // Check if BLOB data is not empty if (!empty($row['bee_audio'])) { // Add audio player to play the MP3 echo '<audio controls>'; echo '<source src="data:audio/mpeg;base64,' . base64_encode($row['bee_audio']) . '" type="audio/mpeg">';

echo 'Your browser does not support the audio element.'; echo '</audio>'; echo '<br>'; echo '<hr>'; } else { echo "No audio available"; } } $conn->close(); ?>

</body> </html>

upload.php

<?php

$dbc = mysqli_connect("DBHost", "DBUser", "Password", "DatabaseName"); $dbc = mysqli_connect("localhost", "u396706841_PicMen", "PICMen707", "u396706841_DataStorage"); if(!$dbc) { die("DATABASE CONNECTION FAILED:" .mysqli_error($dbc)); exit();

}

$db = "u396706841_DataStorage"; $dbs = mysqli_select_db($dbc, $db); if(!$dbs) { die("DATABASE SELECTION FAILED:" .mysqli_error($dbc)); exit();

}

$ID = mysqli_real_escape_string($dbc, $_GET['id']);

$BEEAUDIO = mysqli_real_escape_string($dbc, $_GET['bee_audio']); $FFT = mysqli_real_escape_string($dbc, $_GET['FFT_image']); $DATETIME = mysqli_real_escape_string($dbc, $_GET['current_datetime']); $query = "insert INTO audio_table(id, bee_audio, FFT_image, current_datetime) VALUES ('$ID', '$BEEAUDIO', '$FFT', '$DATETIME')"; if(mysqli_query($dbc, $query)){ echo "Records added successfully"; } else{ echo "ERROR: Could not add records." . $query." ". mysqli_error($dbc); } mysqli_close($dbc); ?>

temphum.php

<html>

<head>

<title>THERE ARE BEES UNDER YOUR SKIN</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jqueryui.css">

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script> </head>

<body>

<style>

form input[type="submit"]:hover { background-color: #0056b3; //Ooooh, user interaction! }

body { //<! background-image: url('https://cdn0.iconfinder.com/data/icons/animalswildlife-line-art-1/128/honeycomb-1024.png'), linear-gradient(to bottom, rgba(0,0,0,0.8), rgba(0,0,0,0.8)) > background-repeat: repeat; background-size: cover; background-position: center center; color: white; position: relative; }

form { text-align: center; }

h1 { text-align: center; font-size: 48; } h3 {text-align: center; font-size: 32; } </style>

<?php

$sd = $_POST["sd"]; //Grab my silly little variables from the query page

$ed = $_POST["ed"]; $startdate = date("Y-m-d", strtotime($sd)); //Convert the queries to dates $enddate = date("Y-m-d", strtotime($ed));

$temp1 = [];

$temp2 = [];

$hum = []; $time = [];

// Connect to database

$host = 'localhost'; $username = 'u396706841_PicMen'; $password = 'PICMen707'; $database = 'u396706841_DataStorage'; $conn = new mysqli($host, $username, $password, $database); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); }

$sql = "SELECT * FROM temp_hum WHERE current_datetime BETWEEN '$startdate' AND '$enddate'";

$result = $conn->query($sql); if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) {

$temp1[] = $row["temp_1"]; $temp2[] = $row["temp_2"]; $hum[] = $row["humidity"]; $time[] = $row["current_datetime"]; } }

$conn->close(); ?>

<canvas id="myChart" width="800" height="400"></canvas> <script> // JavaScript code to render the chart var ctx = document.getElementById('myChart').getContext('2d'); //New chart var myChart = new Chart(ctx, { type: 'line', //Line chart

data: {

labels: <?php echo json_encode($time); ?>, //Label x-axis with time datasets: [{ label: 'Center Temperature (°F)', //subject to change

data: <?php echo json_encode($temp1); ?>, //Create .JSON for reading temp1 values

backgroundColor: 'rgba(255, 0, 0, 0.2)', //temp1 line is red

borderColor: 'rgba(255, 50, 50, 1)', borderWidth: 3

}, { label: 'Outer Temperature (°F)', //subject to change.

data: <?php echo json_encode($temp2); ?>, //Create .JSON for reading temp2 values

backgroundColor: 'rgba(32, 67, 77, 0.2)', //temp2 line is teal

borderColor: 'rgba(0, 128, 128, 1)', borderWidth: 3 }, { label: 'Humidity (%)', //Humidity graph

data: <?php echo json_encode($hum); ?>, //Create .JSON for reading humidity values

backgroundColor: 'rgba(0, 255, 0, 0.2)', //hum line is green

borderColor: 'rgba(50, 255, 50, 1)', borderWidth: 3 }]

},

options: { //backgroundColor: 'blue', scales: { yAxes: [{ ticks: { beginAtZero: true, //Start chart at x=0 } }] } } }); </script> </body>

Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.