From 6b3af717fbb3b42239f6de7d04930c8698321eb5 Mon Sep 17 00:00:00 2001 From: Knuti_in_Paese Date: Tue, 14 Feb 2023 10:34:22 +0100 Subject: [PATCH 1/8] RPi:(new)DTU-name,Disco-handler,ext.Error-handling,sun2mqtt Add disconnect handler for influx and volkszaehler. Change spec. Informations on ahoy.service and ahoy.yml.example. Extented Error handling. Send sun-rise and sun-set information to MQTT. --- tools/rpi/ahoy.service | 3 +- tools/rpi/ahoy.yml.example | 13 ++--- tools/rpi/hoymiles/__main__.py | 47 ++++++++++++++---- tools/rpi/hoymiles/decoders/__init__.py | 17 ++++++- tools/rpi/hoymiles/outputs.py | 63 ++++++++++++++++++++----- 5 files changed, 112 insertions(+), 31 deletions(-) diff --git a/tools/rpi/ahoy.service b/tools/rpi/ahoy.service index 4af9ea89..c7be5bb2 100644 --- a/tools/rpi/ahoy.service +++ b/tools/rpi/ahoy.service @@ -6,8 +6,7 @@ # WorkingDirectory (absolute path to your private ahoy dir) # To change other config parameter, please consult systemd documentation # -# To activate this service, create a link with enable and start the ahoy.service -# $ mkdir -p $HOME/.config/systemd/user +# To activate this service, enable and start ahoy.service # $ systemctl --user enable $(pwd)/ahoy/tools/rpi/ahoy.service # $ systemctl --user status ahoy # $ systemctl --user start ahoy diff --git a/tools/rpi/ahoy.yml.example b/tools/rpi/ahoy.yml.example index 928374de..9301067f 100644 --- a/tools/rpi/ahoy.yml.example +++ b/tools/rpi/ahoy.yml.example @@ -31,7 +31,7 @@ ahoy: QoS: 0 Retain: True last_will: - topic: hoymiles/114172220003 # defaults to 'hoymiles/{serial}' + topic: my_DTU_name # Name of DTU - default: hoymiles/{DTU-serial} payload: "LAST-WILL-MESSAGE: Please check my HOST and Process!" # Influx2 output @@ -96,6 +96,7 @@ ahoy: dtu: serial: 99978563001 + name: my_DTU_name inverters: - name: 'balkon' @@ -103,14 +104,14 @@ ahoy: txpower: 'low' # txpower per inverter (min,low,high,max) mqtt: send_raw_enabled: false # allow inject debug data via mqtt - topic: 'hoymiles/114172221234' # defaults to '{inverter-name}/{serial}' + topic: 'hoymiles/114172220003' # defaults to '{inverter-name}/{serial}' strings: # list all available strings - s_name: 'String 1 left' # String 1 name - s_maxpower: 395 # String 1 max power in Wp + s_maxpower: 395 # String 1 max power in inverter - s_name: 'String 2 right' # String 2 name - s_maxpower: 400 # String 2 max power in Wp + s_maxpower: 400 # String 2 max power in inverter - s_name: 'String 3 up' # String 3 name - s_maxpower: 405 # String 3 max power in Wp + s_maxpower: 405 # String 3 max power in inverter - s_name: 'String 4 down' # String 4 name - s_maxpower: 410 # String 4 max power in Wp + s_maxpower: 410 # String 4 max power in inverter diff --git a/tools/rpi/hoymiles/__main__.py b/tools/rpi/hoymiles/__main__.py index 00608a44..7de4a1a2 100644 --- a/tools/rpi/hoymiles/__main__.py +++ b/tools/rpi/hoymiles/__main__.py @@ -33,6 +33,12 @@ def signal_handler(sig_num, frame): if mqtt_client: mqtt_client.disco() + if influx_client: + influx_client.disco() + + if volkszaehler_client: + volkszaehler_client.disco() + sys.exit(0) signal(SIGINT, signal_handler) # Interrupt from keyboard (CTRL + C) @@ -75,7 +81,6 @@ class SunsetHandler: else: logging.info('Sunset disabled.') - def checkWaitForSunrise(self): if not self.suntimes: return @@ -94,6 +99,23 @@ class SunsetHandler: time.sleep(time_to_sleep) logging.info (f'Woke up...') + def sun_status2mqtt(self, dtu_ser, dtu_name): + if not mqtt_client: + return + local_sunrise = self.suntimes.riselocal(datetime.now()).strftime("%d.%m.%YT%H:%M") + local_sunset = self.suntimes.setlocal(datetime.now()).strftime("%d.%m.%YT%H:%M") + local_zone = self.suntimes.setlocal(datetime.now()).tzinfo._key + if self.suntimes: + mqtt_client.info2mqtt({'topic' : f'{dtu_name}/{dtu_ser}'}, \ + {'dis_night_comm' : 'True', \ + 'local_sunrise' : local_sunrise, \ + 'local_sunset' : local_sunset, + 'local_zone' : local_zone}) + else: + mqtt_client.sun_info2mqtt({'sun_topic': f'{dtu_name}/{dtu_ser}'}, \ + {'dis_night_comm': 'False'}) + + def main_loop(ahoy_config): """Main loop""" inverters = [ @@ -101,7 +123,9 @@ def main_loop(ahoy_config): if not inverter.get('disabled', False)] sunset = SunsetHandler(ahoy_config.get('sunset')) - dtu_ser = ahoy_config.get('dtu', {}).get('serial') + dtu_ser = ahoy_config.get('dtu', {}).get('serial', None) + dtu_name = ahoy_config.get('dtu', {}).get('name', 'hoymiles-dtu') + sunset.sun_status2mqtt(dtu_ser, dtu_name) loop_interval = ahoy_config.get('interval', 1) try: @@ -112,6 +136,11 @@ def main_loop(ahoy_config): t_loop_start = time.time() for inverter in inverters: + if not 'name' in inverter: + inverter['name'] = 'hoymiles' + if not 'serial' in inverter: + logging.error("No inverter serial number found in ahoy.yml - exit") + sys.exit(999) if hoymiles.HOYMILES_DEBUG_LOGGING: logging.info(f'Poll inverter name={inverter["name"]} ser={inverter["serial"]}') poll_inverter(inverter, dtu_ser, do_init, 3) @@ -122,8 +151,6 @@ def main_loop(ahoy_config): if time_to_sleep > 0: time.sleep(time_to_sleep) - except KeyboardInterrupt: - sys.exit() except Exception as e: logging.fatal('Exception catched: %s' % e) logging.fatal(traceback.print_exc()) @@ -284,11 +311,11 @@ def init_logging(ahoy_config): lvl = logging.ERROR elif level == 'FATAL': lvl = logging.FATAL - if hoymiles.HOYMILES_TRANSACTION_LOGGING and hoymiles.HOYMILES_DEBUG_LOGGING: - lvl = logging.DEBUG - if not hoymiles.HOYMILES_TRANSACTION_LOGGING and not hoymiles.HOYMILES_DEBUG_LOGGING: - lvl = logging.INFO + if hoymiles.HOYMILES_TRANSACTION_LOGGING: + lvl = logging.DEBUG logging.basicConfig(filename=fn, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=lvl) + dtu_name = ahoy_config.get('dtu',{}).get('name','hoymiles-dtu') + logging.info(f'start logging for {dtu_name} with level: {logging.root.level}') if __name__ == '__main__': parser = argparse.ArgumentParser(description='Ahoy - Hoymiles solar inverter gateway', prog="hoymiles") @@ -330,14 +357,14 @@ if __name__ == '__main__': # create MQTT - client object mqtt_client = None - mqtt_config = ahoy_config.get('mqtt', {}) + mqtt_config = ahoy_config.get('mqtt', None) if mqtt_config and not mqtt_config.get('disabled', False): from .outputs import MqttOutputPlugin mqtt_client = MqttOutputPlugin(mqtt_config) # create INFLUX - client object influx_client = None - influx_config = ahoy_config.get('influxdb', {}) + influx_config = ahoy_config.get('influxdb', None) if influx_config and not influx_config.get('disabled', False): from .outputs import InfluxOutputPlugin influx_client = InfluxOutputPlugin( diff --git a/tools/rpi/hoymiles/decoders/__init__.py b/tools/rpi/hoymiles/decoders/__init__.py index fa80a3b4..bb32fb07 100644 --- a/tools/rpi/hoymiles/decoders/__init__.py +++ b/tools/rpi/hoymiles/decoders/__init__.py @@ -155,6 +155,7 @@ class StatusResponse(Response): s_exists = False string_id = len(strings) string = {} + string['name'] = self.inv_strings[string_id]['s_name'] for key in self.string_keys: prop = f'dc_{key}_{string_id}' if hasattr(self, prop): @@ -329,7 +330,7 @@ class EventsResponse(UnknownResponse): self.status = struct.unpack('>H', self.response[:2])[0] self.a_text = self.alarm_codes.get(self.status, 'N/A') - logging.info (f' Inverter status: {self.a_text} ({self.status})') + logging.info (f'Inverter status: {self.a_text} ({self.status})') chunk_size = 12 for i_chunk in range(2, len(self.response), chunk_size): @@ -489,6 +490,8 @@ class Hm300Decode0B(StatusResponse): """ String 1 irratiation in percent """ if self.inv_strings is None: return None + if self.inv_strings[0]['s_maxpower'] == 0: + return 0.00 return round(self.unpack('>H', 6)[0]/10/self.inv_strings[0]['s_maxpower']*100, 3) @property @@ -561,6 +564,8 @@ class Hm600Decode0B(StatusResponse): """ String 1 irratiation in percent """ if self.inv_strings is None: return None + if self.inv_strings[0]['s_maxpower'] == 0: + return 0.00 return round(self.unpack('>H', 6)[0]/10/self.inv_strings[0]['s_maxpower']*100, 3) @property @@ -588,6 +593,8 @@ class Hm600Decode0B(StatusResponse): """ String 2 irratiation in percent """ if self.inv_strings is None: return None + if self.inv_strings[1]['s_maxpower'] == 0: + return 0.00 return round(self.unpack('>H', 12)[0]/10/self.inv_strings[1]['s_maxpower']*100, 3) @property @@ -668,6 +675,8 @@ class Hm1200Decode0B(StatusResponse): """ String 1 irratiation in percent """ if self.inv_strings is None: return None + if self.inv_strings[0]['s_maxpower'] == 0: + return 0.00 return round(self.unpack('>H', 8)[0]/10/self.inv_strings[0]['s_maxpower']*100, 3) @property @@ -695,6 +704,8 @@ class Hm1200Decode0B(StatusResponse): """ String 2 irratiation in percent """ if self.inv_strings is None: return None + if self.inv_strings[1]['s_maxpower'] == 0: + return 0.00 return round(self.unpack('>H', 10)[0]/10/self.inv_strings[1]['s_maxpower']*100, 3) @property @@ -722,6 +733,8 @@ class Hm1200Decode0B(StatusResponse): """ String 3 irratiation in percent """ if self.inv_strings is None: return None + if self.inv_strings[2]['s_maxpower'] == 0: + return 0.00 return round(self.unpack('>H', 30)[0]/10/self.inv_strings[2]['s_maxpower']*100, 3) @property @@ -749,6 +762,8 @@ class Hm1200Decode0B(StatusResponse): """ String 4 irratiation in percent """ if self.inv_strings is None: return None + if self.inv_strings[3]['s_maxpower'] == 0: + return 0.00 return round(self.unpack('>H', 32)[0]/10/self.inv_strings[3]['s_maxpower']*100, 3) @property diff --git a/tools/rpi/hoymiles/outputs.py b/tools/rpi/hoymiles/outputs.py index e4754fbc..11971a85 100644 --- a/tools/rpi/hoymiles/outputs.py +++ b/tools/rpi/hoymiles/outputs.py @@ -40,6 +40,7 @@ class InfluxOutputPlugin(OutputPluginFactory): def __init__(self, url, token, **params): """ Initialize InfluxOutputPlugin + https://influxdb-client.readthedocs.io/en/stable/api.html#influxdbclient The following targets must be present in your InfluxDB. This does not automatically create anything for You. @@ -69,8 +70,12 @@ class InfluxOutputPlugin(OutputPluginFactory): self._org = params.get('org', '') self._measurement = params.get('measurement', f'inverter,host={socket.gethostname()}') - client = InfluxDBClient(url, token, bucket=self._bucket) - self.api = client.write_api() + with InfluxDBClient(url, token, bucket=self._bucket) as self.client: + self.api = self.client.write_api() + + def disco(self, **params): + self.client.close() # Shutdown the client + return def store_status(self, response, **params): """ @@ -103,6 +108,9 @@ class InfluxOutputPlugin(OutputPluginFactory): # InfluxDB requires nanoseconds ctime = int(utctime.timestamp() * 1e9) + if HOYMILES_DEBUG_LOGGING: + logging.info(f'InfluxDB: utctime: {utctime}') + # AC Data phase_id = 0 for phase in data['phases']: @@ -136,6 +144,9 @@ class InfluxOutputPlugin(OutputPluginFactory): data_stack.append(f'{measurement},type=YieldToday value={data["yield_today"]/1000:.3f} {ctime}') data_stack.append(f'{measurement},type=Efficiency value={data["efficiency"]:.2f} {ctime}') + if HOYMILES_DEBUG_LOGGING: + #logging.debug(f'INFLUX data to DB: {data_stack}') + pass self.api.write(self._bucket, self._org, data_stack) class MqttOutputPlugin(OutputPluginFactory): @@ -197,6 +208,12 @@ class MqttOutputPlugin(OutputPluginFactory): def disco(self, **params): self.client.loop_stop() # Stop loop self.client.disconnect() # disconnect + return + + def info2mqtt(self, mqtt_topic, mqtt_data): + for mqtt_key in mqtt_data: + self.client.publish(f'{mqtt_topic["topic"]}/{mqtt_key}', mqtt_data[mqtt_key], self.qos, self.ret) + return def store_status(self, response, **params): """ @@ -210,13 +227,18 @@ class MqttOutputPlugin(OutputPluginFactory): """ data = response.__dict__() - topic = f'{data.get("inverter_name", "hoymiles")}/{data.get("inverter_ser", None)}' + topic = params.get('topic', None) + if not topic: + topic = f'{data.get("inverter_name", "hoymiles")}/{data.get("inverter_ser", None)}' + + if HOYMILES_DEBUG_LOGGING: + logging.info(f'MQTT-topic: {topic} data-type: {type(response)}') if isinstance(response, StatusResponse): # Global Head if data['time'] is not None: - self.client.publish(f'{topic}/time', data['time'].strftime("%d.%m.%y - %H:%M:%S"), self.qos, self.ret) + self.client.publish(f'{topic}/time', data['time'].strftime("%d.%m.%YT%H:%M:%S"), self.qos, self.ret) # AC Data phase_id = 0 @@ -234,12 +256,16 @@ class MqttOutputPlugin(OutputPluginFactory): string_id = 0 string_sum_power = 0 for string in data['strings']: - self.client.publish(f'{topic}/emeter-dc/{string_id}/voltage', string['voltage'], self.qos, self.ret) - self.client.publish(f'{topic}/emeter-dc/{string_id}/current', string['current'], self.qos, self.ret) - self.client.publish(f'{topic}/emeter-dc/{string_id}/power', string['power'], self.qos, self.ret) - self.client.publish(f'{topic}/emeter-dc/{string_id}/YieldDay', string['energy_daily'], self.qos, self.ret) - self.client.publish(f'{topic}/emeter-dc/{string_id}/YieldTotal', string['energy_total']/1000, self.qos, self.ret) - self.client.publish(f'{topic}/emeter-dc/{string_id}/Irradiation', string['irradiation'], self.qos, self.ret) + if 'name' in string: + string_name = string['name'].replace(" ","_") + else: + string_name = string_id + self.client.publish(f'{topic}/emeter-dc/{string_name}/voltage', string['voltage'], self.qos, self.ret) + self.client.publish(f'{topic}/emeter-dc/{string_name}/current', string['current'], self.qos, self.ret) + self.client.publish(f'{topic}/emeter-dc/{string_name}/power', string['power'], self.qos, self.ret) + self.client.publish(f'{topic}/emeter-dc/{string_name}/YieldDay', string['energy_daily'], self.qos, self.ret) + self.client.publish(f'{topic}/emeter-dc/{string_name}/YieldTotal', string['energy_total']/1000, self.qos, self.ret) + self.client.publish(f'{topic}/emeter-dc/{string_name}/Irradiation', string['irradiation'], self.qos, self.ret) string_id = string_id + 1 string_sum_power += string['power'] @@ -297,6 +323,9 @@ class VzInverterOutput: ts = int(round(data['time'].timestamp() * 1000)) + if HOYMILES_DEBUG_LOGGING: + logging.info(f'Volkszaehler-Timestamp: {ts}') + # AC Data phase_id = 0 for phase in data['phases']: @@ -329,6 +358,7 @@ class VzInverterOutput: if data['yield_today'] is not None: self.try_publish(ts, f'yield_today', data['yield_today']) self.try_publish(ts, f'efficiency', data['efficiency']) + return def try_publish(self, ts, ctype, value): if not ctype in self.channels: @@ -340,9 +370,12 @@ class VzInverterOutput: url = f'{self.baseurl}/data/{uid}.json?operation=add&ts={ts}&value={value}' if uid == None: if HOYMILES_DEBUG_LOGGING: - logging.warning(f'ctype \"{ctype}\" has no configured uid-value in ahoy.yml') + logging.debug(f'ctype \"{ctype}\" has no configured uid-value in ahoy.yml') return + if HOYMILES_DEBUG_LOGGING: + logging.debug(f'VZ-url: {url}') + try: r = self.session.get(url) if r.status_code == 404: @@ -353,6 +386,7 @@ class VzInverterOutput: raise ValueError(f'Transmit result {url}') except ConnectionError as e: raise ValueError(f'Could not connect VZ-DB {type(e)} {e.keys()}') + return class VolkszaehlerOutputPlugin(OutputPluginFactory): def __init__(self, config, **params): @@ -373,13 +407,17 @@ class VolkszaehlerOutputPlugin(OutputPluginFactory): exit(1) self.session = requests.Session() - self.inverters = dict() + self.inverters = dict() for inverterconfig in config.get('inverters', []): serial = inverterconfig.get('serial') output = VzInverterOutput(inverterconfig, self.session) self.inverters[serial] = output + def disco(self, **params): + self.session.close() # closing the connection + return + def store_status(self, response, **params): """ Publish StatusResponse object @@ -404,3 +442,4 @@ class VolkszaehlerOutputPlugin(OutputPluginFactory): output.store_status(data, self.session) except ValueError as e: logging.warning('Could not send data to volkszaehler instance: %s' % e) + return From a60b6affaea4e1a4567efd1dde86ad95c231ff7f Mon Sep 17 00:00:00 2001 From: tomquist Date: Sun, 5 Mar 2023 11:24:00 +0100 Subject: [PATCH 2/8] Add TSOL-M1600 to firmware collection --- User_Manual.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/User_Manual.md b/User_Manual.md index 529125a0..5ff1339a 100644 --- a/User_Manual.md +++ b/User_Manual.md @@ -304,7 +304,8 @@ To get the information open the URL `/api/record/info` on your AhoyDTU. The info | chehrlic | HM-600 | | 1.0.10 | 2021 | 11-01 | 104 | | | | chehrlic | TSOL-M800de | | 1.0.10 | 2021 | 11-01 | 104 | | | | B5r1oJ0A9G | HM-800 | | 1.0.10 | 2021 | | 104 | | | -| | | | | | | | | | +| B5r1oJ0A9G | HM-800 | | 1.0.10 | 2021 | | 104 | | | +| tomquist | TSOL-M1600 | | 1.0.12 | 2020 | 06-24 | 100 | | | | | | | | | | | | | ## Developer Information about Command Queue From ce81ca8f531f779f44e03eefeb4b9c1d60eaf254 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 7 Mar 2023 21:24:29 +0100 Subject: [PATCH 3/8] add license Readme to have it better visible to all --- LICENSE | 437 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 12 ++ 2 files changed, 449 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..cbe5ad16 --- /dev/null +++ b/LICENSE @@ -0,0 +1,437 @@ +Attribution-NonCommercial-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-ShareAlike 4.0 International Public License +("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-NC-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution, NonCommercial, and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + l. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + m. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + n. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-NC-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the β€œLicensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/README.md b/README.md index c378424c..ecf6b58f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,15 @@ +Shield: [![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa] + +This work is licensed under a +[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa]. + +[![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa] + +[cc-by-nc-sa]: https://creativecommons.org/licenses/by-nc-sa/4.0/deed.de +[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png +[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg + + ![actions/workflows/compile_esp8266.yml](../../actions/workflows/compile_esp8266.yml/badge.svg) ![actions/workflows/compile_development.yml](../../actions/workflows/compile_development.yml/badge.svg) # πŸ– Ahoy! From 9cc0b5b19caba6d3d5f93aa1a1d6c684889a48cb Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 7 Mar 2023 21:31:47 +0100 Subject: [PATCH 4/8] readme update --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ecf6b58f..a5be1ce9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Shield: [![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa] +[![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa] [![Ahoy Dev Build][dev-action-badge]][dev-action-link] This work is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa]. @@ -9,8 +9,9 @@ This work is licensed under a [cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png [cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg +[dev-action-badge]: ../../actions/workflows/compile_esp8266.yml/badge.svg +[dev-action-link]: actions/workflows/compile_development.yml -![actions/workflows/compile_esp8266.yml](../../actions/workflows/compile_esp8266.yml/badge.svg) ![actions/workflows/compile_development.yml](../../actions/workflows/compile_development.yml/badge.svg) # πŸ– Ahoy! ![Logo](https://github.com/grindylow/ahoy/blob/main/doc/logo1_small.png?raw=true) From 6dd6670b137158f6480b9ec16230135e499f16a9 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 7 Mar 2023 21:42:35 +0100 Subject: [PATCH 5/8] readme update --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a5be1ce9..b51439c7 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -[![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa] [![Ahoy Dev Build][dev-action-badge]][dev-action-link] +[![CC BY-NC-SA 3.0][cc-by-nc-sa-shield]][cc-by-nc-sa] [![Ahoy Dev Build][dev-action-badge]][dev-action-link] This work is licensed under a -[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa]. +[Creative Commons Attribution-NonCommercial-ShareAlike 3.0 International License][cc-by-nc-sa]. -[![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa] +[![CC BY-NC-SA 3.0][cc-by-nc-sa-image]][cc-by-nc-sa] -[cc-by-nc-sa]: https://creativecommons.org/licenses/by-nc-sa/4.0/deed.de -[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png -[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg +[cc-by-nc-sa]: https://creativecommons.org/licenses/by-nc-sa/3.0/de/ +[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/3.0/88x31.png +[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%203.0-lightgrey.svg -[dev-action-badge]: ../../actions/workflows/compile_esp8266.yml/badge.svg -[dev-action-link]: actions/workflows/compile_development.yml +[dev-action-badge]: https://github.com/lumapu/ahoy/actions/workflows/compile_development.yml/badge.svg +[dev-action-link]: .github/workflows/compile_development.yml # πŸ– Ahoy! From 6f344458f9b822182a4cb12e35b731558ebaaa2f Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 7 Mar 2023 21:43:50 +0100 Subject: [PATCH 6/8] fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b51439c7..472e7c92 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This work is licensed under a [cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%203.0-lightgrey.svg [dev-action-badge]: https://github.com/lumapu/ahoy/actions/workflows/compile_development.yml/badge.svg -[dev-action-link]: .github/workflows/compile_development.yml +[dev-action-link]: https://github.com/lumapu/ahoy/actions/workflows/compile_development.yml # πŸ– Ahoy! From a6610001a38f3fdeddf98be0e282331fcb3cd56b Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 7 Mar 2023 21:52:25 +0100 Subject: [PATCH 7/8] update readme --- README.md | 12 ++++++------ scripts/gh-action-dev-build-flash.html | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 472e7c92..33ce8964 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -[![CC BY-NC-SA 3.0][cc-by-nc-sa-shield]][cc-by-nc-sa] [![Ahoy Dev Build][dev-action-badge]][dev-action-link] +[![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa] [![Ahoy Dev Build][dev-action-badge]][dev-action-link] This work is licensed under a -[Creative Commons Attribution-NonCommercial-ShareAlike 3.0 International License][cc-by-nc-sa]. +[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa]. -[![CC BY-NC-SA 3.0][cc-by-nc-sa-image]][cc-by-nc-sa] +[![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa] -[cc-by-nc-sa]: https://creativecommons.org/licenses/by-nc-sa/3.0/de/ -[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/3.0/88x31.png -[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%203.0-lightgrey.svg +[cc-by-nc-sa]: https://creativecommons.org/licenses/by-nc-sa/4.0/de/ +[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png +[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg [dev-action-badge]: https://github.com/lumapu/ahoy/actions/workflows/compile_development.yml/badge.svg [dev-action-link]: https://github.com/lumapu/ahoy/actions/workflows/compile_development.yml diff --git a/scripts/gh-action-dev-build-flash.html b/scripts/gh-action-dev-build-flash.html index b6566b27..ea6146db 100644 --- a/scripts/gh-action-dev-build-flash.html +++ b/scripts/gh-action-dev-build-flash.html @@ -10,6 +10,9 @@ Flash | AhoyDTU
+

Development Build (ESP8266 / ESP32)

From 32e26d5e14398450ce6410e9b548881d88afe136 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 7 Mar 2023 22:07:00 +0100 Subject: [PATCH 8/8] fix link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33ce8964..43b31dfe 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This work is licensed under a [![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa] -[cc-by-nc-sa]: https://creativecommons.org/licenses/by-nc-sa/4.0/de/ +[cc-by-nc-sa]: https://creativecommons.org/licenses/by-nc-sa/4.0/deed.de [cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png [cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg