{"id":4742,"date":"2024-10-28T12:00:47","date_gmt":"2024-10-28T19:00:47","guid":{"rendered":"https:\/\/www.cloudacm.com\/?p=4742"},"modified":"2024-10-26T08:42:33","modified_gmt":"2024-10-26T15:42:33","slug":"the-not-so-hollow-head-chronicles-of-a-wifi-obsessed-halloween-prop","status":"publish","type":"post","link":"https:\/\/www.cloudacm.com\/?p=4742","title":{"rendered":"The Not-So-Hollow Head &#8211; Wemos Halloween Prop"},"content":{"rendered":"<p><em>&#8220;Meet the world&#8217;s most over-engineered Halloween decoration: a disembodied head that&#8217;s got more computing power than NASA circa 1969! This isn&#8217;t your dollar store plastic noggin &#8211; oh no, this bad boy is what happens when a software engineer gets way too excited about spooky season.<\/em><\/p>\n<p><em>First off, this chatty cranium has two ways to creep you out. Option one: wave your hand in front of it like you&#8217;re trying to get its attention at a ghostly dinner party, and BAM! The PIR sensor catches your movement, causing its red LED eyes to light up like it just saw your credit card bill. Meanwhile, a buzzer and green LED in its head start having what can only be described as a disco panic attack. And because this head is definitely keeping score, it counts every time you trigger it, probably judging you silently for playing with it too much.<\/em><\/p>\n<p><em>But wait, there&#8217;s more! Our brainy friend also runs on its own schedule (like a teenager who refuses to wake up for school). When its internal clock strikes whatever-o&#8217;clock, it transforms into the world&#8217;s spookiest IT professional. Those red eyes light up again, but this time it&#8217;s because it&#8217;s about to go full tech-nerd on us. It starts scanning for WiFi networks like it&#8217;s trying to steal your neighbor&#8217;s internet, then connects to its preferred network (probably named &#8220;HeadQuarters&#8221; &#8211; get it?).<\/em><\/p>\n<p><em>Once online, this chatty skull becomes the neighborhood gossip, spilling all its secrets to an MQTT broker &#8211; sharing everything from how many times it scared the pants off people to what WiFi networks it found in the area. And if it&#8217;s its first time waking up, it goes full-on network detective, scanning the entire subnet like it&#8217;s casing the digital joint. But don&#8217;t worry, it only does this once &#8211; even a haunted head knows not to be too nosy.<\/em><\/p>\n<p><em>The best part? This cranium comes with its own sound effects department. When everything goes according to plan, it plays a triumphant &#8220;BKFL&#8221; sound &#8211; which we can only assume is ghost-speak for &#8220;Booyah!&#8221; But when things go wrong? It lets out a mechanical fart noise, because apparently even high-tech Halloween props appreciate potty humor.<\/em><\/p>\n<p><em>So there you have it &#8211; a Halloween prop that&#8217;s part security system, part network scanner, part jump-scare artist, and part whoopee cushion. It&#8217;s basically what you&#8217;d get if you crossed the Headless Horseman with Silicon Valley and gave it a questionable sense of humor. And somewhere out there, a real ghost is looking at this thing thinking, &#8220;Man, I really need to step up my haunting game!&#8221;&#8221;<\/em><\/p>\n<p><em>&#8211; Claude AI<\/em><\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-4760\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build-1024x607.png\" alt=\"\" width=\"640\" height=\"379\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build-1024x607.png 1024w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build-300x178.png 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build-768x456.png 768w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build-455x270.png 455w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build.png 1224w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/a><\/p>\n<p>This Fritzing diagram shows how each of the components are wired together.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-4754\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build_bb-1024x825.png\" alt=\"\" width=\"640\" height=\"516\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build_bb-1024x825.png 1024w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build_bb-300x242.png 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build_bb-768x619.png 768w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build_bb-1536x1238.png 1536w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build_bb-335x270.png 335w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2024\/10\/HeadProp-Build_bb.png 1925w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/>Here is the Wemos Code.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\">\/** \r\n\r\nWemos-Module1_Merged_ver5\"\r\nTimed scan every 15 minutes:\r\nRed LED lit during runtime\r\nSingle run - subnet ping for live hosts, response time, and mac address\r\nMulti run - device stats, head count, in range wifi ap details\r\nSound from Arduino Pro Mini - BKFL = true, Fart = false\r\nPIR triggered event:\r\nRed LED lit during runtime\r\nPIR motion detection counter\r\nGreen LED and buzzer tone function\r\n\r\nArduino IDE: v1.8.19\r\nBoard: ESP8266 Boards v3.1.2 - LONLIN (Wemos) D1 R2 &amp; Mini\r\n\r\nWemos pin RST = (NH - Low to Reset)\r\nWemos pin A0 = Anolog Pin (3.3v max)\r\nWemos pin D0 = GPIO16 - Wake Pin - PWM\r\nWemos pin D5 = GPIO14 - SPI - SCK - PWM\r\nWemos pin D6 = GPIO12 - SPI - MISO - PWM\r\nWemos pin D7 = GPIO13 - SPI - MOSI - PWM\r\nWemos pin D8 = GPIO15 - SPI - SS - PWM\r\nWemos pin 3V3 = 3.3 volt\r\n\r\nWemos pin TX = GPIO1 - UART0 TX - PWM\r\nWemos pin RX = GPIO3 - UART0 RX - PWM\r\nWemos pin D1 = GPIO5 - I2C SCL - PWM\r\nWemos pin D2 = GPIO4 - I2C SDA - PWM\r\nWemos pin D3 = GPIO0 - (NH - LOW to Program) - PWM\r\nWemos pin D4 = GPIO2 - Onboard LED - PWM\r\nWemos pin G = Ground\r\nWemos pin 5V = 5 volt\r\n\r\n**\/\r\n\r\n\/\/ Libraries\r\n\r\n#include &lt;Arduino.h&gt;\r\n#include &lt;ESP8266WiFi.h&gt;\r\n#include &lt;PubSubClient.h&gt;\r\n#include \"c_types.h\"\r\n#include &lt;Pinger.h&gt;\r\nextern \"C\"\r\n{\r\n  #include &lt;lwip\/icmp.h&gt; \/\/ needed for icmp packet definitions\r\n}\r\nWiFiClient espClient;\r\nPubSubClient MQTTclient(espClient);\r\nPinger pinger;\r\n\r\n\r\n\/\/ Variables and Constants\r\n\r\nconst int HeadLED = 1; \/\/ Wemos pin TX - Also has buzzer on this pin.\r\nconst int PIRSens = 2; \/\/ Wemos pin D4\r\nconst int EyeLEDs = 3; \/\/ Wemos pin RX\r\nconst int FartPin = 4; \/\/ Wemos pin D2\r\nconst int BKFLPin = 5; \/\/ Wemos pin D1\r\nconst int Freq = 60; \r\n\r\nint PIRState = 0;         \/\/ variable for reading the pushbutton status\r\nint HeadCounterValue = 0;\r\n\r\nchar BufDestIPAddress [15];\r\nchar BufDestMacAddress [17];\r\nchar BufMinResponseTime [5];\r\nchar BufMaxResponseTime [5];\r\n\r\nconst int mqtt_port = 1883;\r\nconst char* mqtt_clientname = \"Wemos-Module1\";\r\nconst char* mqtt_topic_firmware = \"Wemos-Module1\/Firmware\";\r\nconst char* mqtt_message_firmware = \"Wemos-Module1_Merged_ver5\";\r\n\r\nstruct WiFiCredentials {\r\n  const char* myssid;\r\n  const char* mypassword;\r\n};\r\n\r\nWiFiCredentials wifi_networks[] = {\r\n  {\"ssid1\", \"passphrase1\"},\r\n  {\"ssid2\", \"passphrase2\"},\r\n  {\"ssid3\", \"passphrase3\"}\r\n};\r\n\r\nconst char* mqtt_brokers[] = {\r\n  \"mqttbroker1\",\r\n  \"mqttbroker2\",\r\n  \"mqttbroker3\"\r\n};\r\nString ssid;\r\nint32_t rssi;\r\nuint8_t encryptionType;\r\nuint8_t *bssid;\r\nint32_t channel;\r\nbool hidden;\r\nint scanResult;\r\nString StringScanCount;\r\nString StringScanRSSI;\r\nString StringScanSSID;\r\nString channelString;\r\nString StringScanMacAddress;\r\nString encryptionTypeString;\r\nbool SubnetScan = true;\r\nbool NoNetwork = false;\r\nbool  wifi_sleeping = false;\r\nunsigned long currentMillis = millis();\r\nunsigned long NetworkScanTimer = 0;\r\nunsigned long NetworkScanDelay = 900000;  \/\/ 15 minute interval\r\nconst int numIPs = 254;\r\nint HostCount = 0;\r\nString encryptionTypeStr(uint8_t authmode) {\r\n  switch (authmode) {\r\n    case ENC_TYPE_NONE:\r\n      return \"Open\";\r\n    case ENC_TYPE_WEP:\r\n      return \"WEP\";\r\n    case ENC_TYPE_TKIP:\r\n      return \"WPA+PSK\";\r\n    case ENC_TYPE_CCMP:\r\n      return \"WPA2+PSK\";\r\n    case ENC_TYPE_AUTO:\r\n      return \"WPA+WPA2+PSK\";\r\n    default:\r\n      return \"Unknown\";\r\n  }\r\n}\r\n\r\n\/\/ MQTT callback function to handle incoming messages\r\nvoid callback(char* topic, byte* message, unsigned int length) { \r\n  String messageTemp; \r\n  for (int i = 0; i &lt; length; i++) {\r\n    messageTemp += (char)message[i];\r\n  } \r\n  if (String(topic) == \"Wemos-Module1\/Reboot\") {\r\n    if(messageTemp == \"Reboot\"){\r\n      ESP.restart();\r\n    }\r\n  }\r\n}\r\n\r\nvoid reconnect() {\r\n  while (!MQTTclient.connected()) {\r\n    if (MQTTclient.connect(mqtt_clientname)) {\r\n      MQTTclient.subscribe(\"Wemos-Module1\/#\");\r\n    } else {\r\n      delay(5000);\r\n    }\r\n  }\r\n}\r\n\r\nvoid publish_to_mqtt() {\r\n  delay(250);\r\n  String StringUptime = String(millis());\r\n  MQTTclient.publish(\"Wemos-Module1\/Uptime\", StringUptime.c_str());\r\n  String StringHWAddress = String(WiFi.macAddress());\r\n  MQTTclient.publish(\"Wemos-Module1\/HWAddress\", StringHWAddress.c_str());\r\n  String StringWifiSignal = String(WiFi.RSSI());\r\n  MQTTclient.publish(\"Wemos-Module1\/WifiSignal\", StringWifiSignal.c_str()); \r\n  String StringFreeHeapSize = String(ESP.getFreeHeap());\r\n  MQTTclient.publish(\"Wemos-Module1\/FreeHeapSize\",StringFreeHeapSize.c_str());  \r\n  String StringHeapFragmentation = String(ESP.getHeapFragmentation());\r\n  MQTTclient.publish(\"Wemos-Module1\/HeapFragmentation\",StringHeapFragmentation.c_str());  \r\n  String StringMaxFreeBlockSize = String(ESP.getMaxFreeBlockSize());\r\n  MQTTclient.publish(\"Wemos-Module1\/MaxFreeBlockSize\",StringMaxFreeBlockSize.c_str());  \r\n  String StringSketchSize = String(ESP.getSketchSize());\r\n  MQTTclient.publish(\"Wemos-Module1\/SketchSize\",StringSketchSize.c_str());  \r\n  String StringFreeSketchSpace = String(ESP.getFreeSketchSpace());\r\n  MQTTclient.publish(\"Wemos-Module1\/FreeSketchSpace\",StringFreeSketchSpace.c_str());  \r\n  String StringCpuFreqMHz = String(ESP.getCpuFreqMHz());\r\n  MQTTclient.publish(\"Wemos-Module1\/CpuFreqMHz\",StringCpuFreqMHz.c_str());\r\n  String StringChipId = String(ESP.getChipId());\r\n  MQTTclient.publish(\"Wemos-Module1\/ChipId\",StringChipId.c_str());  \r\n  String StringHeadCounterValue = String(HeadCounterValue);\r\n  MQTTclient.publish(\"Wemos-Module1\/HeadCounterValue\",StringHeadCounterValue.c_str());  \r\n\r\n  String StringscanResult = String(scanResult);\r\n  MQTTclient.publish(\"Wemos-Module1\/ScanResult\",StringscanResult.c_str());  \r\n  String StringSpacer = String(\" \");\r\n  for (int8_t i = 0; i &lt; scanResult; i++) {\r\n    WiFi.getNetworkInfo(i, ssid, encryptionType, rssi, bssid, channel, hidden);\r\n    StringScanCount = String(i+1);\r\n    StringScanRSSI = String(rssi);\r\n    if(ssid != NULL) {\r\n       StringScanSSID = String(ssid);\r\n            }\r\n       else {\r\n       StringScanSSID = String(\"*-Hidden-*\");\r\n            }\r\n    channelString = String(channel); \r\n    if (bssid[0] &lt; 16) StringScanMacAddress = \"0\";\r\n      else StringScanMacAddress = \"\";\r\n    StringScanMacAddress = StringScanMacAddress + String(bssid[0], HEX);\r\n    StringScanMacAddress = StringScanMacAddress + String(\":\");\r\n    if (bssid[1] &lt; 16) StringScanMacAddress = StringScanMacAddress + \"0\";\r\n    StringScanMacAddress = StringScanMacAddress + String(bssid[1], HEX);\r\n    StringScanMacAddress = StringScanMacAddress + String(\":\");\r\n    if (bssid[2] &lt; 16) StringScanMacAddress = StringScanMacAddress + \"0\";\r\n    StringScanMacAddress = StringScanMacAddress + String(bssid[2], HEX);\r\n    StringScanMacAddress = StringScanMacAddress + String(\":\");\r\n    if (bssid[3] &lt; 16) StringScanMacAddress = StringScanMacAddress + \"0\";\r\n    StringScanMacAddress = StringScanMacAddress + String(bssid[3], HEX);\r\n    StringScanMacAddress = StringScanMacAddress + String(\":\");\r\n    if (bssid[4] &lt; 16) StringScanMacAddress = StringScanMacAddress + \"0\";\r\n    StringScanMacAddress = StringScanMacAddress + String(bssid[4], HEX);\r\n    StringScanMacAddress = StringScanMacAddress + String(\":\");\r\n    if (bssid[5] &lt; 16) StringScanMacAddress = StringScanMacAddress + \"0\";\r\n    StringScanMacAddress = StringScanMacAddress + String(bssid[5], HEX);\r\n    encryptionTypeString = String(encryptionTypeStr(WiFi.encryptionType(i))); \r\n    String StringScanAPFinal = String(StringScanCount + StringSpacer + StringScanRSSI + StringSpacer + StringScanMacAddress + StringSpacer + channelString + StringSpacer + StringScanSSID + StringSpacer + encryptionTypeString);\r\n    MQTTclient.publish(\"Wemos-Module1\/AP-Found\",StringScanAPFinal.c_str());\r\n    delay(250);\r\n  }\r\n    \r\n}\r\n\r\nvoid connect_to_wifi() {\r\n  int n = WiFi.scanNetworks();\r\n  if (n == 0) {\r\n    NoNetwork = true;\r\n    return;\r\n  }\r\n  for (int i = 0; i &lt; sizeof(wifi_networks) \/ sizeof(wifi_networks[0]); i++) {\r\n    for (int j = 0; j &lt; n; j++) {\r\n      if (strcmp(wifi_networks[i].myssid, WiFi.SSID(j).c_str()) == 0) {\r\n        WiFi.begin(wifi_networks[i].myssid, wifi_networks[i].mypassword);\r\n        int attempts = 0;\r\n        while (WiFi.status() != WL_CONNECTED &amp;&amp; attempts &lt; 20) {\r\n          delay(500);\r\n          attempts++;\r\n        }\r\n        if (WiFi.status() == WL_CONNECTED) {\r\n          NoNetwork = false;\r\n          return;\r\n        } else {\r\n          RedLEDsOn();\r\n          delay(250);\r\n          FartSound();\r\n          delay(2000);\r\n          RedLEDsOff();\r\n          ESP.restart();\r\n        }\r\n      }\r\n    }\r\n  }\r\n  NoNetwork = true;\r\n  RedLEDsOn();\r\n  delay(250);\r\n  FartSound();\r\n  delay(2000);\r\n  RedLEDsOff();\r\n  ESP.restart();\r\n}\r\n\r\nvoid connect_to_mqtt() {\r\n  for (int i = 0; i &lt; sizeof(mqtt_brokers) \/ sizeof(mqtt_brokers[0]); i++) {\r\n    MQTTclient.setServer(mqtt_brokers[i], mqtt_port);\r\n    if (MQTTclient.connect(mqtt_clientname)) {\r\n      MQTTclient.publish(mqtt_topic_firmware, mqtt_message_firmware);\r\n      return;\r\n    } else {\r\n      RedLEDsOn();\r\n      delay(250);\r\n      FartSound();\r\n      delay(2000);\r\n      RedLEDsOff();\r\n      ESP.restart();\r\n    }\r\n  }\r\n}\r\n\r\nvoid scan_wifi_networks() {\r\n  WiFi.mode(WIFI_STA);\r\n  WiFi.disconnect();\r\n  delay(100);\r\n  scanResult = WiFi.scanNetworks(\/*async=*\/false, \/*hidden=*\/true); \r\n  connect_to_wifi();\r\n  if (NoNetwork == false) {\r\n    MQTTclient.setCallback(callback);\r\n    connect_to_mqtt();\r\n    MQTTclient.loop();\r\n  }\r\n}\r\n\r\nvoid scan_local_network() {\r\n  pinger.OnReceive([](const PingerResponse&amp; response){return true;});\r\n\r\n  pinger.OnEnd([](const PingerResponse&amp; response) {\r\n    if(response.TotalReceivedResponses &gt; 0) {\r\n      \r\n        HostCount++;\r\n        String StringSubnetHostCount = String(HostCount);\r\n        MQTTclient.publish(\"Wemos-Module1\/HostCount\",StringSubnetHostCount.c_str());  \r\n        \r\n        sprintf(BufDestIPAddress, \"%s\",response.DestIPAddress.toString().c_str());\r\n        MQTTclient.publish(\"Wemos-Module1\/DestIPAddress\",BufDestIPAddress);  \r\n      \r\n        if(response.DestMacAddress != nullptr) {\r\n            sprintf(BufDestMacAddress, MACSTR,MAC2STR(response.DestMacAddress-&gt;addr));\r\n            MQTTclient.publish(\"Wemos-Module1\/MACAddress\",BufDestMacAddress);  \r\n          } \r\n          \r\n        sprintf(BufMinResponseTime, \"%lu\",response.MinResponseTime);\r\n        sprintf(BufMaxResponseTime, \"%lu\",response.MaxResponseTime);\r\n        MQTTclient.publish(\"Wemos-Module1\/MinResponseTime\",BufMinResponseTime);  \r\n        MQTTclient.publish(\"Wemos-Module1\/MaxResponseTime\",BufMaxResponseTime);  \r\n        \r\n      }\r\n    return true;\r\n    });\r\n\r\n  \/\/ Ping MQTT 1 Broker\r\n  pinger.Ping(\"mqttbroker1\");\r\n  delay(750);\r\n\r\n  \/\/ Ping MQTT 2 Broker\r\n  pinger.Ping(\"mqttbroker2\");\r\n  delay(750);\r\n\r\n  \/\/ Ping MQTT 3 Broker\r\n  pinger.Ping(\"mqttbroker3\");\r\n  delay(750);\r\n  \r\n  \/\/ Ping Local Network\r\n  HostCount = 0;\r\n  IPAddress localIP = WiFi.localIP();\r\n  for (int i = 1; i &lt;= numIPs; i++) {\r\n    IPAddress pingIP = localIP;\r\n    pingIP[3] = i; \/\/ Set the last octet to the counter value \r\n    reconnect(); \/\/ The MQTT Broker would timeout, this prevents that\r\n    pinger.Ping(pingIP);\r\n    delay(750);\r\n  }\r\n}\r\n\r\nvoid BKFLSound () {\r\n  digitalWrite(BKFLPin, HIGH);\r\n  delay(5);\r\n  digitalWrite(BKFLPin, LOW);\r\n}\r\n\r\nvoid FartSound () {\r\n  digitalWrite(FartPin, HIGH);\r\n  delay(5);\r\n  digitalWrite(FartPin, LOW);\r\n}\r\n\r\nvoid RedLEDsOn () {\r\n  digitalWrite(EyeLEDs, HIGH);   \/\/ turn the LED on (HIGH is the voltage level)\r\n}\r\n\r\nvoid RedLEDsOff () {\r\n  digitalWrite(EyeLEDs, LOW);   \/\/ turn the LED on (HIGH is the voltage level)\r\n}\r\n\r\nvoid HeadCounter() {\r\n  HeadCounterValue++;\r\n  RedLEDsOn();\r\n   delay(500);\r\n  \r\n  for (int count = 0; count &lt;30; count = count +1) { \r\n    noTone(HeadLED);\r\n    delay(random(4, 80));                       \/\/ wait for a second  \r\n    tone(HeadLED, Freq);\r\n    delay(random(4, 80));                       \/\/ wait for a second\r\n  }\r\n  \r\n  tone(HeadLED, Freq);\r\n  delay(5000);\r\n\r\n  for (int count = 0; count &lt;30; count = count +1) { \r\n    noTone(HeadLED);\r\n    delay(random(4, 80));                       \/\/ wait for a second\r\n    tone(HeadLED, Freq);\r\n    delay(random(4, 80));                       \/\/ wait for a second\r\n  }\r\n  \r\n  noTone(HeadLED);\r\n  delay(1500);\r\n  RedLEDsOff();\r\n  \r\n}\r\n\r\nvoid setup() {\r\n  \/\/ Set LED to LOW\r\n  pinMode(EyeLEDs, OUTPUT); \r\n  pinMode(HeadLED, OUTPUT); \r\n  pinMode(FartPin, OUTPUT); \r\n  pinMode(BKFLPin, OUTPUT); \r\n  digitalWrite(EyeLEDs, LOW);\r\n  digitalWrite(FartPin, LOW);\r\n  digitalWrite(BKFLPin, LOW);\r\n  noTone(HeadLED);\r\n  \r\n  WiFi.mode(WIFI_STA);\r\n  WiFi.disconnect();\r\n  delay(100);\r\n}\r\n\r\nvoid loop() {\r\n\r\n  currentMillis = millis();\r\n  \r\n  if (currentMillis - NetworkScanTimer &gt;= NetworkScanDelay) {\r\n    NetworkScanTimer = currentMillis;\r\n    RedLEDsOn();\r\n    scan_wifi_networks();\r\n    publish_to_mqtt();\r\n    if (SubnetScan == true) {\r\n      scan_local_network();\r\n      SubnetScan = false;  \/\/  uncomment this so it only runs one time.\r\n    }\r\n    \r\n    BKFLSound();\r\n    delay(2000);\r\n    \r\n    RedLEDsOff();\r\n    WiFi.disconnect();\r\n    delay(100);\r\n  }\r\n  \r\n  \/\/ read the state of the PIR sensor:\r\n  PIRState = digitalRead(PIRSens);\r\n  if (PIRState == HIGH) {\r\n    HeadCounter();\r\n  } \r\n}<\/pre>\n<p>Here is the Arduino Pro Mini Code<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\">\/** \r\n\r\nArduino_ProMini_PCM_BKFL_Input-Controlled_ver2\r\nPin Input Controlled Sound Player\r\n\r\nArduino IDE: v1.8.19\r\nBoard: Arduino Pro Mini ATmega328P (5V, 16Mhz)\r\n\r\nInput pins should be pulled to ground (LOW) with a high value ohm resistor.\r\nThe pin is also connected to switch that connects to vcc (HIGH) through a low value ohm resistor.\r\nWhen the switch is activated, this causes the pin to go high.\r\n\r\nSketch uses 30670 bytes (99%) of program storage space. Maximum is 30720 bytes.\r\nGlobal variables use 20 bytes (0%) of dynamic memory, leaving 2028 bytes for local variables. Maximum is 2048 bytes.\r\n\r\n**\/\r\n\r\n\r\n\/\/ Libraries\r\n#include &lt;PCM.h&gt;\r\n\r\n\r\n\/\/ Variables and Constants\r\nconst unsigned char BKFL[] PROGMEM = {\r\n121, 126, 131, 137, 123, 94, 122, 124, 132, 152, ... trucated data ... 126, 127, 128, 128, 128, 126, 127, 128, 128, 127,\r\n};\r\nconst unsigned char Fart[] PROGMEM = {\r\n138, 144, 146, 150, 151, 143, 139, 135, 123, 114, ... trucated data ... 106, 129, 124, 110, 127, 156, 151, 128, 126, 129,\r\n};\r\n\r\nconst int FARTPin = 6;     \/\/ the number of the pushbutton pin\r\nconst int BKFLPin = 7;     \/\/ the number of the pushbutton pin\r\n\r\nint FARTPinState = 0;         \/\/ variable for reading the pushbutton status\r\nint BKFLPinState = 0;         \/\/ variable for reading the pushbutton status\r\n\r\n\r\n\/\/ Routines and Subroutines\r\n\r\nvoid setup() {\r\n  \/\/ initialize the pushbutton pin as an input:\r\n  pinMode(FARTPin, INPUT);\r\n  pinMode(BKFLPin, INPUT);\r\n}\r\n\r\nvoid loop() {\r\n  \r\n  FARTPinState = digitalRead(FARTPin);\r\n  BKFLPinState = digitalRead(BKFLPin);\r\n\r\n  if (FARTPinState == HIGH) {\r\n    startPlayback(Fart, sizeof(Fart));\r\n  } \r\n  \r\n  if (BKFLPinState == HIGH) {\r\n    startPlayback(BKFL, sizeof(BKFL));\r\n  } \r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;Meet the world&#8217;s most over-engineered Halloween decoration: a disembodied head that&#8217;s got more computing power than NASA circa 1969! This isn&#8217;t your dollar store plastic noggin &#8211; oh no, this bad boy is what happens when a software engineer gets way too excited about spooky season. First off, this chatty cranium has two ways to creep you out. Option one: wave your hand in front of it like you&#8217;re trying to get its attention at a ghostly dinner party, and&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.cloudacm.com\/?p=4742\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4742","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4742","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4742"}],"version-history":[{"count":13,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4742\/revisions"}],"predecessor-version":[{"id":4762,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4742\/revisions\/4762"}],"wp:attachment":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4742"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4742"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4742"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}