diff --git a/api/MacAddress.cpp b/api/MacAddress.cpp
new file mode 100644
index 00000000..16fc3625
--- /dev/null
+++ b/api/MacAddress.cpp
@@ -0,0 +1,146 @@
+#include <MacAddress.h>
+#include <stdio.h>
+#include <Print.h>
+
+//Default constructor, blank mac address.
+MacAddress::MacAddress() {
+    _mac.val = 0;
+}
+
+MacAddress::MacAddress(uint64_t mac) {
+    _mac.val = mac;
+}
+
+MacAddress::MacAddress(const uint8_t *macbytearray) {
+    memcpy(_mac.bytes, macbytearray, sizeof(_mac.bytes));
+}
+
+MacAddress::MacAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6) {
+    _mac.bytes[0] = b1;
+    _mac.bytes[1] = b2;
+    _mac.bytes[2] = b3;
+    _mac.bytes[3] = b4;
+    _mac.bytes[4] = b5;
+    _mac.bytes[5] = b6;
+}
+
+//Parse user entered string into MAC address
+bool MacAddress::fromCStr(const char *buf) {
+  char cs[18];
+  char *token;
+  char *next; //Unused but required
+  int i;
+
+  strncpy(cs, buf, sizeof(cs)); //strtok modifies the buffer: copy to working buffer.
+
+  for(i=0; i<sizeof(_mac.bytes); i++) {
+    token = strtok((i==0) ? cs : NULL, ":");    //Find first or next token
+    if(!token) {                                //No more tokens found
+        return false;
+    }
+    _mac.bytes[i] = strtol(token, &next, 16);
+  }
+  return true;
+}
+
+//Parse user entered string into MAC address
+bool MacAddress::fromString(const String &macstr) {
+    return fromCStr(macstr.c_str());
+}
+
+//Copy MAC into 6 byte array
+void MacAddress::toBytes(uint8_t *buf) {
+    memcpy(buf, _mac.bytes, sizeof(_mac.bytes));
+}
+
+//Print MAC address into a C string.
+//MAC: Buffer must be at least 18 chars
+int MacAddress::toCStr(char *buf) {
+    return sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+        _mac.bytes[0], _mac.bytes[1], _mac.bytes[2],
+        _mac.bytes[3], _mac.bytes[4], _mac.bytes[5]);
+}
+
+String MacAddress::toString() const {
+    char buf[18];
+    sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+        _mac.bytes[0], _mac.bytes[1], _mac.bytes[2],
+        _mac.bytes[3], _mac.bytes[4], _mac.bytes[5]);
+    return String(buf);
+}
+
+uint64_t MacAddress::Value() {
+    return _mac.val;
+}
+
+//Allow getting individual octets of the address. e.g. uint8_t b0 = ma[0];
+uint8_t MacAddress::operator[](int index) const {
+    index = EnforceIndexBounds(index);
+    return _mac.bytes[index];
+}
+
+//Allow setting individual octets of the address. e.g. ma[2] = 255;
+uint8_t& MacAddress::operator[](int index) {
+    index = EnforceIndexBounds(index);
+    return _mac.bytes[index];
+}
+
+//Overloaded copy operator: init MacAddress object from byte array
+MacAddress& MacAddress::operator=(const uint8_t *macbytearray) {
+    memcpy(_mac.bytes, macbytearray, sizeof(_mac.bytes));
+    return *this;
+}
+
+//Overloaded copy operator: init MacAddress object from uint64_t
+MacAddress& MacAddress::operator=(uint64_t macval) {
+    _mac.val = macval;
+    return *this;
+}
+
+//Compare class to byte array
+bool MacAddress::operator==(const uint8_t *macbytearray) const {
+    return !memcmp(_mac.bytes, macbytearray, sizeof(_mac.bytes));
+}
+
+//Allow comparing value of two classes
+bool MacAddress::operator==(const MacAddress& mac2) const {
+    return _mac.val == mac2._mac.val;
+}
+
+//Type converter object to uint64_t [same as .Value()]
+MacAddress::operator uint64_t() const {
+    return _mac.val;
+}
+
+//Type converter object to read only pointer to mac bytes. e.g. const uint8_t *ip_8 = ma;
+MacAddress::operator const uint8_t*() const {
+    return _mac.bytes;
+}
+
+//Type converter object to read only pointer to mac value. e.g. const uint32_t *ip_64 = ma;
+MacAddress::operator const uint64_t*() const {
+    return &_mac.val;
+}
+
+size_t MacAddress::printTo(Print& p) const
+{
+    size_t n = 0;
+    for(int i = 0; i < 6; i++) {
+        if(i){
+            n += p.print(':');
+        }
+        n += p.printf("%02X", _mac.bytes[i]);
+    }
+    return n;
+}
+
+//Bounds checking
+int MacAddress::EnforceIndexBounds(int i) const {
+    if(i < 0) {
+        return 0;
+    }
+    if(i >= sizeof(_mac.bytes)) {
+        return sizeof(_mac.bytes)-1;
+    }
+    return i;
+}
diff --git a/api/MacAddress.h b/api/MacAddress.h
new file mode 100644
index 00000000..1356ab70
--- /dev/null
+++ b/api/MacAddress.h
@@ -0,0 +1,73 @@
+//-----------------------------------------------------------------------------
+// MacAddress.h - class to make it easier to handle BSSID and MAC addresses.
+// 
+// Copyright 2022 David McCurley
+// Licensed under the Apache License, Version 2.0 (the "License").
+// You may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+//     
+// Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+//   limitations under the License.
+//-----------------------------------------------------------------------------
+
+#ifndef MacAddress_h
+#define MacAddress_h
+
+#include <stdint.h>
+#include <WString.h>
+#include <Printable.h>
+
+// A class to make it easier to handle and pass around 6-byte BSSID and MAC addresses.
+class MacAddress : public Printable {
+private:
+    union {
+        struct {
+            uint8_t align[2];
+            uint8_t bytes[6];
+        };
+        uint64_t val;
+    } _mac;
+
+public:
+    MacAddress();
+    MacAddress(uint64_t mac);
+    MacAddress(const uint8_t *macbytearray);
+    MacAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6);
+    virtual ~MacAddress() {}
+    bool fromCStr(const char *buf);
+    bool fromString(const String &macstr);
+    void toBytes(uint8_t *buf);
+    int  toCStr(char *buf);
+    String toString() const;
+    uint64_t Value();
+
+    uint8_t operator[](int index) const;
+    uint8_t& operator[](int index);
+    MacAddress& operator=(const uint8_t *macbytearray);
+    MacAddress& operator=(uint64_t macval);
+    bool operator==(const uint8_t *macbytearray) const;
+    bool operator==(const MacAddress& mac2) const;
+    operator uint64_t() const;
+    operator const uint8_t*() const;
+    operator const uint64_t*() const;
+
+    virtual size_t printTo(Print& p) const;
+
+    // future use in Arduino Networking 
+    friend class EthernetClass;
+    friend class UDP;
+    friend class Client;
+    friend class Server;
+    friend class DhcpClass;
+    friend class DNSClient;
+
+private:
+    int EnforceIndexBounds(int i) const;
+};
+
+#endif
diff --git a/api/MacAddress8.cpp b/api/MacAddress8.cpp
new file mode 100644
index 00000000..7406bee8
--- /dev/null
+++ b/api/MacAddress8.cpp
@@ -0,0 +1,147 @@
+#include <MacAddress8.h>
+#include <stdio.h>
+#include <Print.h>
+
+//Default constructor, blank mac address.
+MacAddress8::MacAddress8() {
+    _mac.val = 0;
+}
+
+MacAddress8::MacAddress8(uint64_t mac) {
+    _mac.val = mac;
+}
+
+MacAddress8::MacAddress8(const uint8_t *macbytearray) {
+    memcpy(_mac.bytes, macbytearray, sizeof(_mac.bytes));
+}
+
+MacAddress8::MacAddress8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8) {
+    _mac.bytes[0] = b1;
+    _mac.bytes[1] = b2;
+    _mac.bytes[2] = b3;
+    _mac.bytes[3] = b4;
+    _mac.bytes[4] = b5;
+    _mac.bytes[5] = b6;
+    _mac.bytes[6] = b7;
+    _mac.bytes[7] = b8;
+}
+
+//Parse user entered string into MAC address
+bool MacAddress8::fromCStr(const char *buf) {
+  char cs[24];
+  char *token;
+  char *next; //Unused but required
+  int i;
+
+  strncpy(cs, buf, sizeof(cs)); //strtok modifies the buffer: copy to working buffer.
+
+  for(i=0; i<sizeof(_mac.bytes); i++) {
+    token = strtok((i==0) ? cs : NULL, ":");    //Find first or next token
+    if(!token) {                                //No more tokens found
+        return false;
+    }
+    _mac.bytes[i] = strtol(token, &next, 16);
+  }
+  return true;
+}
+
+//Parse user entered string into MAC address
+bool MacAddress8::fromString(const String &macstr) {
+    return fromCStr(macstr.c_str());
+}
+
+//Copy MAC into 8 byte array
+void MacAddress8::toBytes(uint8_t *buf) {
+    memcpy(buf, _mac.bytes, sizeof(_mac.bytes));
+}
+
+//Print MAC address into a C string.
+//EUI-64: Buffer must be at least 24 chars
+int MacAddress8::toCStr(char *buf) {
+    return sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
+        _mac.bytes[0], _mac.bytes[1], _mac.bytes[2], _mac.bytes[3],
+        _mac.bytes[4], _mac.bytes[5], _mac.bytes[6], _mac.bytes[7]);
+}
+
+String MacAddress8::toString() const {
+    char buf[24];
+    sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
+        _mac.bytes[0], _mac.bytes[1], _mac.bytes[2], _mac.bytes[3],
+        _mac.bytes[4], _mac.bytes[5], _mac.bytes[6], _mac.bytes[7]);
+    return String(buf);
+}
+
+uint64_t MacAddress8::Value() {
+    return _mac.val;
+}
+
+uint8_t MacAddress8::operator[](int index) const {
+    index = EnforceIndexBounds(index);
+    return _mac.bytes[index];
+}
+
+//Allow setting individual octets of the address. e.g. ma[2] = 255;
+uint8_t& MacAddress8::operator[](int index) {
+    index = EnforceIndexBounds(index);
+    return _mac.bytes[index];
+}
+
+//Overloaded copy operator: init MacAddress object from byte array
+MacAddress8& MacAddress8::operator=(const uint8_t *macbytearray) {
+    memcpy(_mac.bytes, macbytearray, sizeof(_mac.bytes));
+    return *this;
+}
+
+//Overloaded copy operator: init MacAddress object from uint64_t
+MacAddress8& MacAddress8::operator=(uint64_t macval) {
+    _mac.val = macval;
+    return *this;
+}
+
+//Compare class to byte array
+bool MacAddress8::operator==(const uint8_t *macbytearray) const {
+    return !memcmp(_mac.bytes, macbytearray, sizeof(_mac.bytes));
+}
+
+//Allow comparing value of two classes
+bool MacAddress8::operator==(const MacAddress8& mac2) const {
+    return _mac.val == mac2._mac.val;
+}
+
+//Type converter object to uint64_t [same as .Value()]
+MacAddress8::operator uint64_t() const {
+    return _mac.val;
+}
+
+//Type converter object to read only pointer to mac bytes. e.g. const uint8_t *ip_8 = ma;
+MacAddress8::operator const uint8_t*() const {
+    return _mac.bytes;
+}
+
+//Type converter object to read only pointer to mac value. e.g. const uint32_t *ip_64 = ma;
+MacAddress8::operator const uint64_t*() const {
+    return &_mac.val;
+}
+
+size_t MacAddress8::printTo(Print& p) const
+{
+    size_t n = 0;
+    for(int i = 0; i < 8; i++) {
+        if(i){
+            n += p.print(':');
+        }
+        n += p.printf("%02X", _mac.bytes[i]);
+    }
+    return n;
+}
+
+//Bounds checking
+int MacAddress8::EnforceIndexBounds(int i) const {
+    if(i < 0) {
+        return 0;
+    }
+    if(i >= sizeof(_mac.bytes)) {
+        return sizeof(_mac.bytes)-1;
+    }
+    return i;
+}
diff --git a/api/MacAddress8.h b/api/MacAddress8.h
new file mode 100644
index 00000000..360ce8c9
--- /dev/null
+++ b/api/MacAddress8.h
@@ -0,0 +1,70 @@
+//-----------------------------------------------------------------------------
+// MacAddress8.h - class to make it easier to handle 8-byte EUI-64 addresses.
+// 
+// Copyright 2022 David McCurley
+// Licensed under the Apache License, Version 2.0 (the "License").
+// You may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//     http://www.apache.org/licenses/LICENSE-2.0
+//     
+// Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+//   limitations under the License.
+//-----------------------------------------------------------------------------
+
+#ifndef MacAddress8_h
+#define MacAddress8_h
+
+#include <stdint.h>
+#include <WString.h>
+#include <Printable.h>
+
+// A class to make it easier to handle and pass around 8-byte EUI-64(used for IEEE 802.15.4) addresses. See <esp_mac.h>.
+class MacAddress8 : public Printable {
+private:
+    union {
+        uint8_t bytes[8];
+        uint64_t val;
+    } _mac;
+
+public:
+    MacAddress8();
+    MacAddress8(uint64_t mac);
+    MacAddress8(const uint8_t *macbytearray);
+    MacAddress8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7, uint8_t b8);
+    virtual ~MacAddress8() {}
+    bool fromCStr(const char *buf);
+    bool fromString(const String &macstr);
+    void toBytes(uint8_t *buf);
+    int  toCStr(char *buf);
+    String toString() const;
+    uint64_t Value();
+
+    uint8_t operator[](int index) const;
+    uint8_t& operator[](int index);
+    MacAddress8& operator=(const uint8_t *macbytearray);
+    MacAddress8& operator=(uint64_t macval);
+    bool operator==(const uint8_t *macbytearray) const;
+    bool operator==(const MacAddress8& mac2) const;
+    operator uint64_t() const;
+    operator const uint8_t*() const;
+    operator const uint64_t*() const;
+
+    virtual size_t printTo(Print& p) const;
+
+    // future use in Arduino Networking 
+    friend class EthernetClass;
+    friend class UDP;
+    friend class Client;
+    friend class Server;
+    friend class DhcpClass;
+    friend class DNSClient;
+
+private:
+    int EnforceIndexBounds(int i) const;
+};
+
+#endif