diff --git a/CHANGELOG.md b/CHANGELOG.md
index c69a7117..2a2099c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,30 +1,16 @@
 # Changelog
 
-## [0.3.9a1](https://github.com/OpenVoiceOS/skill-ovos-date-time/tree/0.3.9a1) (2024-11-11)
+## [0.4.0a1](https://github.com/OpenVoiceOS/skill-ovos-date-time/tree/0.4.0a1) (2024-11-12)
 
-[Full Changelog](https://github.com/OpenVoiceOS/skill-ovos-date-time/compare/0.3.8a3...0.3.9a1)
+[Full Changelog](https://github.com/OpenVoiceOS/skill-ovos-date-time/compare/0.3.9...0.4.0a1)
 
-**Merged pull requests:**
-
-- fix: drop lingua-franca [\#71](https://github.com/OpenVoiceOS/skill-ovos-date-time/pull/71) ([JarbasAl](https://github.com/JarbasAl))
-
-## [0.3.8a3](https://github.com/OpenVoiceOS/skill-ovos-date-time/tree/0.3.8a3) (2024-11-10)
-
-[Full Changelog](https://github.com/OpenVoiceOS/skill-ovos-date-time/compare/0.3.8a2...0.3.8a3)
-
-## [0.3.8a2](https://github.com/OpenVoiceOS/skill-ovos-date-time/tree/0.3.8a2) (2024-11-10)
-
-[Full Changelog](https://github.com/OpenVoiceOS/skill-ovos-date-time/compare/0.3.8a1...0.3.8a2)
-
-## [0.3.8a1](https://github.com/OpenVoiceOS/skill-ovos-date-time/tree/0.3.8a1) (2024-11-10)
+**Implemented enhancements:**
 
-[Full Changelog](https://github.com/OpenVoiceOS/skill-ovos-date-time/compare/0.3.7...0.3.8a1)
+- play sound - when hour changes [\#47](https://github.com/OpenVoiceOS/skill-ovos-date-time/issues/47)
 
 **Merged pull requests:**
 
-- Nl-nl translation [\#69](https://github.com/OpenVoiceOS/skill-ovos-date-time/pull/69) ([gitlocalize-app[bot]](https://github.com/apps/gitlocalize-app))
-- Nl-NL translation [\#68](https://github.com/OpenVoiceOS/skill-ovos-date-time/pull/68) ([gitlocalize-app[bot]](https://github.com/apps/gitlocalize-app))
-- Nl-nl translation [\#67](https://github.com/OpenVoiceOS/skill-ovos-date-time/pull/67) ([gitlocalize-app[bot]](https://github.com/apps/gitlocalize-app))
+- feat: hour chime [\#66](https://github.com/OpenVoiceOS/skill-ovos-date-time/pull/66) ([JarbasAl](https://github.com/JarbasAl))
 
 
 
diff --git a/MANIFEST.in b/MANIFEST.in
index 17379123..7415bc78 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,8 +1,5 @@
-recursive-include dialog *
-recursive-include vocab *
 recursive-include locale *
 recursive-include res *
-recursive-include qt5 *
-recursive-include skill *
+recursive-include gui *
 include *.json
 include *.txt
\ No newline at end of file
diff --git a/README.md b/README.md
index ad8f5aab..a9e7fdeb 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,7 @@
 Get the time, date, day of the week
 
 ## About 
-Get the local time or time for major cities around the world.  Times
-are given in 12-hour (2:30 pm) or 24-hour format (14:30) based on the
-Time Format setting in your `mycroft.conf`
-
+Get the local time or time for major cities around the world.  Times are given in 12-hour (2:30 pm) or 24-hour format (14:30) based on the Time Format setting in your `mycroft.conf`
 
 ## Examples 
 * "What time is it?"
@@ -16,8 +13,29 @@ Time Format setting in your `mycroft.conf`
 * "How many days until July 4th"
 * "What day is Memorial Day 2020?"
 
+## Configuration
+
+You can adjust certain aspects of this skill's behavior by configuring the `settings.json` file. 
+
+2 sound files are included with the skill, `"casio-watch.wav"` and `"clock-chime.mp3"`, to audibly signal when the hour changes
+
+Below is an example configuration file with explanations for each option.
+
+```json
+{
+    "play_hour_chime": true,
+    "hour_sound": "clock-chime.mp3"
+}
+```
+
+- **`play_hour_chime`**: (boolean) Enables or disables the hourly chime notification. If `true`, the skill will play an audio chime at the start of every hour. Default is `false`.
+- **`hour_sound`**: (string) Specifies the file path to the audio file used for the hourly chime. By default, it points to `casio-watch.wav` in the `res` folder. You can customize this with the path to any audio file you prefer.
+
 ## Credits 
-Mycroft AI (@MycroftAI)
+
+- [casio-watch.wav by @Pablobd](https://freesound.org/people/Pablobd/sounds/492481/) under the [CC0 1.0 Universal License](https://creativecommons.org/publicdomain/zero/1.0/)
+- [clock-chime.mp3 by @ecfike](https://pixabay.com/sound-effects/clock-chime-88027/) under the [Pixabay Content License](https://pixabay.com/service/license-summary/)
+- Original skill by Mycroft AI (@MycroftAI)
 
 ## Category
 **Daily**
diff --git a/__init__.py b/__init__.py
index 10ef134b..38c08890 100644
--- a/__init__.py
+++ b/__init__.py
@@ -11,8 +11,8 @@
 # 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.
-
 import datetime
+import os
 import re
 from typing import Optional
 
@@ -67,8 +67,63 @@ def runtime_requirements(self):
                                    no_gui_fallback=True)
 
     def initialize(self):
-        """Initialize the skill by pre-loading lingua-franca."""
+        """Initialize the skill by pre-loading language settings and scheduling
+        the hourly chime.
+
+        This method is called automatically when the skill starts, preloading
+        language-related formatting for date and time and setting up the initial
+        scheduling for the hourly chime event.
+        """
         date_time_format.cache(self.lang)
+        self._schedule_hour_chime()
+
+    def _handle_play_hour_chime(self, message: Message):
+        """Play the hourly chime audio and re-schedule the next chime event.
+
+        Args:
+            message (Message): message object
+
+        This method checks if the hourly chime setting is enabled. If it is, it
+        plays the specified chime audio. Then, it re-schedules the next hourly
+        chime event.
+        """
+        if self.play_hour_chime:
+            self.play_audio(self.hour_chime, instant=True)
+        self._schedule_hour_chime()
+
+    def _schedule_hour_chime(self):
+        """Schedule the next hourly chime event for the start of the next hour.
+
+        This method calculates the time for the upcoming hour, setting it as
+        the scheduled time for the next chime event.
+        """
+        n = now_local() + datetime.timedelta(hours=1)
+        self.schedule_event(self._handle_play_hour_chime,
+                            when=datetime.datetime(year=n.year, month=n.month, day=n.day,
+                                                   hour=n.hour, minute=0, second=0))
+
+    @property
+    def play_hour_chime(self) -> bool:
+        """Check if the hourly chime setting is enabled.
+
+        Returns:
+            bool: True if the chime should be played on the hour, False otherwise.
+        """
+        return self.settings.get("play_hour_chime", False)
+
+    @property
+    def hour_chime(self) -> str:
+        """Get the file path for the hourly chime sound.
+
+        Returns:
+            str: The file path to the chime audio file. If not set in settings,
+            defaults to 'casio-watch.wav' in the 'res' folder.
+        """
+        snd = self.settings.get("hour_sound", "casio-watch.wav")
+        if not os.path.isfile(snd):
+            snd2 = f"{os.path.dirname(__file__)}/res/{snd}"
+            snd = snd2 if os.path.isfile(snd2) else snd
+        return snd
 
     @property
     def use_24hour(self):
@@ -95,7 +150,8 @@ def _extract_location(self, utt: str) -> str:
                             pass
         return None
 
-    def _get_timezone_from_builtins(self, location_string: str) -> datetime.tzinfo:
+    @staticmethod
+    def _get_timezone_from_builtins(location_string: str) -> Optional[datetime.tzinfo]:
         """Get timezone from built-in resources."""
         if "/" not in location_string:
             try:
@@ -130,7 +186,7 @@ def _get_timezone_from_table(self, location_string: str) -> Optional[datetime.tz
                 return pytz.timezone(timezones[timezone].strip())
         return None
 
-    def _get_timezone_from_fuzzymatch(self, location_string: str) -> datetime.tzinfo:
+    def _get_timezone_from_fuzzymatch(self, location_string: str) -> Optional[datetime.tzinfo]:
         """Fuzzymatch a location against the pytz timezones.
 
         The pytz timezones consists of
@@ -187,7 +243,7 @@ def get_timezone_in_location(self, location_string: str) -> datetime.tzinfo:
     ######################################################################
     # utils
     def get_datetime(self, location: str = None,
-                     anchor_date: datetime.datetime = None) -> datetime.datetime:
+                     anchor_date: datetime.datetime = None) -> Optional[datetime.datetime]:
         """return anchor_date/now_local at location/session_tz"""
         if location:
             tz = self.get_timezone_in_location(location)
@@ -430,7 +486,7 @@ def show_date_mark1(self, dt: datetime.datetime):
         show = self.get_display_date(anchor_date=dt)
         LOG.debug(f"sending date to mk1 {show}")
         self.bus.emit(Message("ovos.mk1.display_date",
-                             {"text": show}))
+                              {"text": show}))
 
     def show_date_gui(self, dt: datetime.datetime, location: str):
         self.gui.clear()
@@ -454,7 +510,7 @@ def show_time(self, display_time: str):
     def show_time_mark1(self, display_time: str):
         LOG.debug(f"Emitting ovos.mk1.display_time with time: {display_time}")
         self.bus.emit(Message("ovos.mk1.display_time",
-                             {"text": display_time}))
+                              {"text": display_time}))
 
     def show_time_gui(self, display_time):
         """ Display time on the GUI. """
diff --git a/res/casio-watch.wav b/res/casio-watch.wav
new file mode 100644
index 00000000..f51fcef1
Binary files /dev/null and b/res/casio-watch.wav differ
diff --git a/res/clock-chime.mp3 b/res/clock-chime.mp3
new file mode 100644
index 00000000..3b9610e7
Binary files /dev/null and b/res/clock-chime.mp3 differ
diff --git a/setup.py b/setup.py
index 49d3e010..fa00f0e7 100755
--- a/setup.py
+++ b/setup.py
@@ -30,9 +30,9 @@ def get_requirements(requirements_filename: str):
 
 
 def find_resource_files():
-    resource_base_dirs = ("locale", "gui")
+    resource_base_dirs = ("locale", "gui", "res")
     base_dir = path.dirname(__file__)
-    package_data = ["*.json"]
+    package_data = ["*.json", "*.mp3", "*.wav"]
     for res in resource_base_dirs:
         if path.isdir(path.join(base_dir, res)):
             for (directory, _, files) in walk(path.join(base_dir, res)):
diff --git a/version.py b/version.py
index c759aba7..1b5d2672 100644
--- a/version.py
+++ b/version.py
@@ -1,6 +1,6 @@
 # START_VERSION_BLOCK
 VERSION_MAJOR = 0
-VERSION_MINOR = 3
-VERSION_BUILD = 9
-VERSION_ALPHA = 0
+VERSION_MINOR = 4
+VERSION_BUILD = 0
+VERSION_ALPHA = 1
 # END_VERSION_BLOCK