 // Starts at or just above zero (within the first 4-minute cycle) to help avoid collisions between units after mass power-up.
 // Wraps at its maximum (0xff) value.
 static uint8_t minuteCount;
-
 
 // Indicate that the system is broken in an obvious way (distress flashing the main LED).
 // DOES NOT RETURN.



#ifdef ALLOW_CC1_SUPPORT_RELAY
// Send a CC1 Alert message with this unit's house code via the RFM23B.
bool sendCC1AlertByRFM23B()
  {
#if !defined(ENABLE_OTSECUREFRAME_ENCODING_SUPPORT)
  OTProtocolCC::CC1Alert a = OTProtocolCC::CC1Alert::make(FHT8V.nvGetHC1(), FHT8V.nvGetHC2());

  // FAILED if fallen through to here.
  return(false);
  }
#endif // ALLOW_CC1_SUPPORT_RELAY

#ifdef ALLOW_CC1_SUPPORT_RELAY
// True if a poll response is needed.
// Cleared upon successful send.
static bool pollResponseNeeded;
// Send a CC1 poll response message with this unit's house code; returns false on failure.
bool sendCC1PollResponse()
  {
  // Respond to the hub with sensor data.
  // Can use read() for very freshest values at risk of some delay/cost.
  const uint8_t hc1 = FHT8V.nvGetHC1();
  const uint8_t hc2 = FHT8V.nvGetHC2();
#ifdef HUMIDITY_SENSOR_SUPPORT
  const uint8_t rh = RelHumidity.read() >> 1; // Scale from [0,100] to [0,50] for TX.
#else
  const uint8_t rh = 0; // RH% not available.
#endif
  const uint8_t tp = (uint8_t) constrain(extDS18B20_0.read() >> 3, 0, 199); // Scale to to 1/2C [0,100[ for TX.
  const uint8_t tr = (uint8_t) constrain(TemperatureC16.read() >> 2, 0, 199); // Scale from 1/16C to 1/4C [0,50[ for TX.
  const uint8_t al = AmbLight.read() >> 2; // Scale from [0,255] to [1,62] for TX (allow value coercion at extremes).
  const bool s = getSwitchToggleStateCO();
  const bool w = (fastDigitalRead(BUTTON_LEARN2_L) != LOW); // BUTTON_LEARN2_L high means open circuit means door/window open.
  const bool sy = !NominalRadValve.isInNormalRunState(); // Assume only non-normal FHT8V state is 'syncing'.
  OTProtocolCC::CC1PollResponse r =
      OTProtocolCC::CC1PollResponse::make(hc1, hc2, rh, tp, tr, al, s, w, sy);
  // Send message back to hub.
  // Hub can poll again if it does not see the response.
  // TODO: may need to insert a delay to allow hub to be ready if use of read() above is not enough.
  uint8_t txbuf[OTProtocolCC::CC1PollResponse::primary_frame_bytes+1]; // More than large enough for preamble + sync + alert message.
  const uint8_t bodylen = r.encodeSimple(txbuf, sizeof(txbuf), true);
#if 1 && defined(DEBUG)
  OTV0P2BASE::serialPrintlnAndFlush(F("polled"));
#endif
#if !defined(ENABLE_OTSECUREFRAME_ENCODING_SUPPORT)
  // Non-secure: send raw frame as-is.
  // Send at default power...  One going missing won't hurt that much.
  if(!PrimaryRadio.sendRaw(txbuf, bodylen))
    { OTV0P2BASE::serialPrintlnAndFlush(F("!TX fail")); return(false); } // FAIL
#else
  // Secure: wrap frame in encrypted layer...
  uint8_t key[16];
  if(!OTV0P2BASE::getPrimaryBuilding16ByteSecretKey(key))
    { OTV0P2BASE::serialPrintlnAndFlush(F("!TX key")); return(false); } // FAIL
  const OTRadioLink::SimpleSecureFrame32or0BodyTXBase::fixed32BTextSize12BNonce16BTagSimpleEnc_ptr_t e = OTAESGCM::fixed32BTextSize12BNonce16BTagSimpleEnc_DEFAULT_STATELESS;
  uint8_t sbuf[OTRadioLink::SecurableFrameHeader::maxSmallFrameSize];
  const uint8_t sbodylen = secureTXState.generateSecureOStyleFrameForTX(sbuf, sizeof(sbuf), OTRadioLink::FTS_RESERVED_A, lenTXID, txbuf, bodylen, e, NULL, key);
  const bool success = (0 != sbodylen) && PrimaryRadio.sendRaw(sbuf+1, sbodylen-1);
#if 1 && defined(DEBUG)
  if(!success) { OTV0P2BASE::serialPrintlnAndFlush(F("!TX A")); }
  else { OTV0P2BASE::serialPrintlnAndFlush(F("TX A")); }
#endif
  if(success)
    {
    // Note successful dispatch of response.
    pollResponseNeeded = false;
    return(true);
    }
#endif // !defined(ENABLE_OTSECUREFRAME_ENCODING_SUPPORT)
  // FAILED if fallen through to here.
  return(false);
  }
#endif // ALLOW_CC1_SUPPORT_RELAY


#ifdef ALLOW_CC1_SUPPORT_RELAY_IO // REV9 CC1 relay...
// Do basic static LED setting.
